Software Design Patterns
– What & Why
Example Pattern:
Publisher-Subscriber (a.k.a. Observer)
What Developers Do With Software
(besides development)
Understand
Maintain (fix bugs)
Upgrade (add new features)
29 trang |
Chia sẻ: candy98 | Lượt xem: 474 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Software Engineering - Lecture 15: Design Patterns 1 - Anh Dao Nam, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
SOFTWARE ENGINEERING
Lecture 15
Design Patterns 1
MBA Course Notes
Dr. ANH DAO NAM
1
Software Engineering
Slides are from Ivan Marsic and Thomas E. Potok, modified by Anh Dao Nam
Textbooks:
Bruegge & Dutoit: Object-Oriented Software Engineering: Using UML,
Patterns and Java, Third Edition, Prentice Hall, 2010.
Miles & Hamilton: Learning UML 2.0, O’Reilly Media, 2006.
Some interesting books for the advanced material include:
R. Pressman, Software Engineering - A Practitioner's Approach, 6th ed.,
2005
C. Ghezzi, M. Jazayeri, and D. Mandriolo, Fundamentals of Software
Engineering. Prentice Hall, second ed., 2002
A. Endres and D. Rombach, A Handbook of Software and Systems
Engineering. The Fraunhofer IESE Series on Software Engineering,
Pearson Education Ltd., 2003.
S. Robertson and J. C. Robertson, Mastering the Requirements Process.
Addison-Wesley Professional, second ed., 2006.
I. Jacobson, G. Booch, and J. Rumbaugh, The Unified Software
Development Process. Addison-Wesley Professional, 1999.
K. Beck and C. Andres, Extreme Programming Explained. Addison-Wesley,
2004.
2
Topics
Software Design Patterns
– What & Why
Example Pattern:
Publisher-Subscriber (a.k.a. Observer)
3
What Developers Do With Software
(besides development)
Understand
Maintain (fix bugs)
Upgrade (add new features)
4
The Power of Patterns
5
CN NIB MAP PLE
The Power of Patterns
6
The Power of Patterns
7
CNN IBM APPLE
The Power of Patterns
8
The Power of Patterns
9
CN NIB MAP PLE
CNN IBM APPLE
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.)
10
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
11
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.
12
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)
13
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
14
Publisher-Subscriber Pattern
A.k.a. “Observer”
Disassociates unrelated responsibilities
Helps simplify/remove complex
conditional logic and allow seamless
future adding of new cases
Based on “Indirect Communication”
15
?
T F
Request- vs. Event-Based Comm.
16
Client Server
Request: doSomething( info ) Request: getInfo()
Info
Src
Doerinfo
(1) Request: subscribe()
Info
Src
Doer
(2) event( info )
(a) (b) (c)
Direct Communication Indirect Comm.
“Before” == A Scenario Suitable for
Applying the Pub-Sub Pattern
17
Event Detector
detectEvent()
Doer1.tellMeWhatToDo()
Doer2.tellMeWhatToDo()
DoerType1
tellMeWhatToDo()
DoerType2
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
“After” == Responsibilities After Applying
the Pub-Sub Pattern
18
Publisher
detectEvent()
subscriber.receive(Event)
Subscriber
receiveEvent()
subscribers : List
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!
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
19
Publisher-Subscriber Pattern
Controller (receives key-code)
Key Checker (checks validity, i.e.,
classifies: valid/invalid)
Publishes the classification result to
“subscribers”
Lock Control
Light Control
Alarm Control
Do the work based on the event
classification outcome
20
PUBLISHER
SUBSCRIBERS
( Assumed: subscription step first )
Pub-Sub Pattern
21
(a) (b)
Publisher
Knowing Responsibilities:
• Knows event source(s)
• Knows interested obj’s (subscribers)
Doing Responsibilities:
• Registers/Unregisters subscribers
• Notifies the subscribers of events
Subscriber
Knowing Responsibilities:
• Knows event types of interest
• Knows publisher(s)
Doing Responsibilities:
• Registers/Unregisters with publishers
• Processes received event notifications
Type1Subscriber
+ receive()
«interface»
Subscriber
+ receive()
«interface»
Publisher
+ subscribe()
+ unsubscribe()
Type1Publisher
+ subscribe()
+ unsubscribe()
Type2Publisher
+ subscribe()
+ unsubscribe()
subscribers
*
Unlock Use Case
22
From Chapter 2
«destroy»
opt
k := create()
sk := getNext()
logTransaction(k, val)
activate(“lock”)
: Controller : Checker : KeyStorage : DeviceCtrl : Logger: PhotoObsrv
dl := isDaylight()
alt
[else]
enterKey()
k : Key
val := checkKey(k)
loop
activate(“bulb”)
val == true
dl == false
compare()
[for all stored keys]
numOfAttempts++
alt numOfAttempts == maxNumOfAttempts
activate(“alarm”)
denyMoreAttempts()
[else]
prompt: "try again"
Refactoring to Publisher-Subscriber
23
1. Subscribe for appropriate events
Pub Sub-1
Sub-n
Pub Sub-1
2. When event occurs:
(a) Classify: keyIsValid / keyIsInvalid
(b) Notify only the subscribers for the detected event class
Sub-n
If a new device is added -- just write a new class; NO modification of the Publisher!
No need to consider the “appropriateness” of calling the “servers”
SubscriberEvent type
keyIsValid
keyIsInvalid
itIsDarkInside
.
.
.
LockCtrl, LightCtrl
AlarmCtrl
LightCtrl
Conditional logic is decided here, at design time,
instead of run time
Design-time decisions are better than runtime decisions,
because they can be easier checked if they “work”
(before the product is developed)
Pub-Sub: Unlock Use Case
24
soundAlarm()
opt
opt
k := create()
sk := getNext()
: Controller : Checker : KeyStorage : LockCtrl : Logger: PhotoSObs
dl := isDaylight()
alt
[else]
enterKey()
k : Key
checkKey(k)
loop
: LightCtrl : AlarmCtrl
setLit(true)
valid == true
compare()
dl == false
keyIsValid()loop
keyIsValid()
loop keyIsInvalid()
keyIsInvalid()
keyIsValid()
for all KeyIsValid subscribers
for all KeyIsInvalid subscribers
keyIsInvalid()prompt:
"try again"
numOfAttempts++
numOfAttempts == maxNumOfAttempts
From Hub-and-Spokes (Star) to Token
Passing (Cascading) Architecture
25
create()
getNext()
: Checker
: KeyStorage
: LockCtrl
: Logger
: PhotoSObs
: Key
checkKey()
: LightCtrl
: AlarmCtrl
: Controller
logTransaction()
setOpen()
isDaylight()
setLit()soundAlarm()
(a)
create()
getNext(): Checker
: KeyStorage
: LockCtrl
: Logger
: PhotoSObs
: Key
checkKey()
: LightCtrl
: AlarmCtrl
: Controller keyIsValid()
isDaylight()
keyIsInvalid()
(b)
Pub-Sub reduced the class coupling:
Before:
After:
Design Patterns: Delegation
26
Client asks for service
Custodian initializes the pattern
Instantiation of the
Design Pattern
collection of objects
working to provide service
Alternative names for Custodian are Assembler or Initializer
Pub-Sub: Initialization
27
: Controller : Checker : LockCtrl : Logger: LightCtrl : AlarmCtrl
subscribeKeyIsValid()
subscribeKeyIsValid()
subscribeKeyIsInvalid()
subscribeKeyIsValid()
subscribeKeyIsInvalid()
create()
subscribeKeyIsInvalid() A method call
that passes a
reference to the
Checker
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!
28
Q&A
29