Design Patterns - ECE

Download Report

Transcript Design Patterns - ECE

LECTURE 17: Design Patterns
Publisher-Subscriber
Ivan Marsic
Rutgers University
1
Topics
• Software Design Patterns
– What & Why
• Example Pattern:
Publisher-Subscriber (a.k.a. Observer)
2
What Developers Do With
Software
(besides development)
• Understand
• Maintain (fix bugs)
• Upgrade (add new features)
3
The Power of Patterns
CN
NIB
MAP
PLE
4
The Power of Patterns
5
The Power of Patterns
CNN
IBM
APPLE
6
The Power of Patterns
7
The Power of Patterns
CN
NIB
CNN
MAP
IBM
PLE
APPLE
8
Software Design Patterns
• Design Patterns help anticipate
change
• Change is bad when there are
unrelated reasons to change a
software module/class
– Unrelated reasons are usually because of
unrelated responsibilities
• Another target is complex conditional
logic (If-Then-Else statements, etc.)
9
What May Change & How
• What changes in real world are business
rules  customer requests changes in
software
• Changes in the small—changes in object
responsibilities towards other objects
–
–
–
–
Number of responsibilities
Data type, or method signature
Business rules
Conditions for provision/fulfillment of responsibilities
• Sometimes change is regular (follows simple
rules), such as new object state defined, or
another object needs to be notified about
something
10
Object Responsibilities
(toward other objects)
• Knowing something (memorization of
data or object attributes)
• Doing something on its own (computation
programmed in a “method”)
– Business rules for implementing business policies
and procedures
• Calling methods of other objects
(communication by sending messages)
– Calling constructor methods; this is special because
the caller must know the appropriate parameters for
initialization of the new object.
11
Patterns for Tackling
Responsibilities
• Delegating “knowing” and associated
“doing” responsibilities (State)
• Delegating “calling” responsibilities
(Command, Publisher-Subscriber)
• Delegating non-essential “doing”
responsibilities (when “doing”
responsibility incrementally modified)
(Decorator)
12
Key Issues
• When a pattern is needed/applicable?
• How to measure if a pattern-based
solution is better?
• When to avoid patterns because may
make things worse?
•  All of the above should be
answered in terms of object
responsibilities before/after a
pattern is applied
13
Publisher-Subscriber Pattern
• A.k.a. “Observer”
• Disassociates unrelated
responsibilities
T
?
F
• Helps simplify/remove complex
conditional logic and allow seamless
future adding of new cases
• Based on “Indirect Communication”
14
Request- vs. Event-Based Comm.
Request: doSomething( info )
Client
Server
Request: getInfo()
Info
Src
info
Doer
(1) Request: subscribe()
Info
Src
Doer
(2) event( info )
(a)
(b)
Direct Communication
(c)
Indirect Comm.
15
“Before” == A Scenario Suitable
for Applying the Pub-Sub Pattern
Event Detector
DoerType1
DoerType2
…
…
…
…
detectEvent()
tellMeWhatToDo()
…
tellMeWhatToDo()
…
Doer1.tellMeWhatToDo()
Doer2.tellMeWhatToDo()
…
…
…
…
Responsibilities
Doing:
• Detect events
Calling:
• Tell Doer-1 what to do
• Tell Doer-2 what to do
unrelated!
 unrelated reasons to change the Event Detector:
 When event detection needs to change or extend
 When new doer types need to be told what to do
16
“After” == Responsibilities After
Applying the Pub-Sub Pattern
Publisher
Subscriber
subscribers : List
…
…
…
detectEvent()
receiveEvent()
…
subscriber.receive(Event)
…
…
…
Unrelated responsibilities of the Event Detector (now Publisher) are dissociated:
 When event detection needs to change or extend  change Publisher
 When new doer types need to be added  add an new Subscriber type
(Subscribers need not be told what to do – they know what to do when a given event occurs!
17
Publisher-Subscriber Pattern
• Focused on classifying events
– The focus in on the “Publisher” object and the
“environment” that it is observing
– Example key events in safe home access:
• Entered key is valid
• Entered key is invalid
• Instead of making decisions & issuing
orders to Doers/Subscribers
– Focusing on other objects’ work: deciding when it
is appropriate to call each one
18
Publisher-Subscriber Pattern
PUBLISHER
• Controller (receives key-code)
Key Checker (checks validity, i.e.,
classifies: valid/invalid)
– Publishes the classification result to “subscribers”
SUBSCRIBERS
• Lock Control
Light Control
Alarm Control
– Do the work based on the event classification
outcome
( Assumed: subscription step first )
19
Pub-Sub Pattern
Publisher
Knowing Responsibilities:
• Knows event source(s)
• Knows interested obj’s (subscribers)
Doing Responsibilities:
• Registers/Unregisters subscribers
• Notifies the subscribers of events
«interface»
Publisher
+ subscribe()
+ unsubscribe()
*
subscribers
«interface»
Subscriber
+ receive()
Subscriber
Knowing Responsibilities:
• Knows event types of interest
• Knows publisher(s)
Doing Responsibilities:
• Registers/Unregisters with publishers
• Processes received event notifications
(a)
Type1Publisher
Type2Publisher
Type1Subscriber
+ subscribe()
+ unsubscribe()
+ subscribe()
+ unsubscribe()
+ receive()
(b)
20
From Chapter 2
Unlock Use Case
: Controller
enterKey()
k : Key
: Checker
: KeyStorage
: DeviceCtrl
: PhotoObsrv
: Logger
k := create()
val := checkKey(k)
loop
[for all stored keys]
sk := getNext()
compare()
logTransaction(k, val)
«destroy»
alt
val == true
activate(“lock”)
dl := isDaylight()
opt
[else]
alt
dl == false
activate(“bulb”)
numOfAttempts++
numOfAttempts == maxNumOfAttempts
denyMoreAttempts()
activate(“alarm”)
[else]
prompt: "try again"
21
Refactoring to Publisher-Subscriber
Conditional logic is decided here, at design time,
instead of run time
1. Subscribe for appropriate events
Pub
Sub-1
Sub-n
Event type
Subscriber
keyIsValid
LockCtrl, LightCtrl
keyIsInvalid
AlarmCtrl
itIsDarkInside
.
.
.
LightCtrl
Sub-n
Pub
Sub-1
No need to consider the “appropriateness” of calling the “servers”
2. When event occurs:
(a) Classify: keyIsValid / keyIsInvalid
(b) Notify only the subscribers for the detected event class
If a new device is added -- just write a new class; NO modification of the Publisher!
Design-time decisions are better than runtime decisions,
because they can be easier checked if they “work”
(before the product is developed)
22
Pub-Sub: Unlock Use Case
: Controller
enterKey()
k : Key
: Checker
: KeyStorage
: LockCtrl
: PhotoSObs
: LightCtrl
: AlarmCtrl
: Logger
k := create()
checkKey(k)
loop
sk := getNext()
compare()
alt
valid == true
for all KeyIsValid subscribers
loop
keyIsValid()
keyIsValid()
keyIsValid()
dl := isDaylight()
opt
dl == false
setLit(true)
[else]
loop
prompt:
"try again"
for all KeyIsInvalid subscribers
keyIsInvalid()
numOfAttempts++
keyIsInvalid()
opt
numOfAttempts == maxNumOfAttempts
soundAlarm()
keyIsInvalid()
23
From Hub-and-Spokes (Star) to Token
Passing (Cascading) Architecture
: Key
: KeyStorage
getNext()
Before:
: Checker
create()
checkKey()
: Logger
: Controller
logTransaction()
After:
setOpen()
: LockCtrl
isDaylight()
soundAlarm()
setLit()
: AlarmCtrl
create()
: Key
: Checker
getNext()
: KeyStorage
: PhotoSObs
: LightCtrl
checkKey()
: Controller
keyIsValid()
keyIsInvalid()
(a)
: LockCtrl
: AlarmCtrl
Pub-Sub reduced the class coupling:
: Logger
: LightCtrl
isDaylight()
(b)
: PhotoSObs
24
Design Patterns: Delegation
Custodian
initializes the pattern
Instantiation of the
Design Pattern
Client
asks for service
collection of objects
working to provide service
Alternative names for Custodian are Assembler or Initializer
25
Pub-Sub: Initialization
: Controller
: Checker
: LockCtrl
: LightCtrl
: AlarmCtrl
: Logger
create()
subscribeKeyIsInvalid()
A method call
that passes a
reference to the
Checker
subscribeKeyIsValid()
subscribeKeyIsValid()
subscribeKeyIsInvalid()
subscribeKeyIsValid()
subscribeKeyIsInvalid()
26
Practical Issues
1. Do not design for patterns first
– Reaching any kind of solution is the priority;
solution optimization should be secondary
2. Refactor the solution to patterns
– E.g., to reduce the complexity of the program’s
conditional logic
•
Uncritical use of patterns may yield
worse solutions!
27