Software Engineering Lecture Slides - ECE

advertisement
LECTURE 7: Object Oriented Design
Ivan Marsic
Rutgers University
Topics
• Assigning Responsibilities to Objects
• Design Principles
• Expert Doer
• High Cohesion
• Low Coupling
• Business Policies
• Class Diagram
2
System Sequence Diagrams
We already worked with interaction diagrams: System Sequence Diagrams
: System
User
Timer
«initiating actor»
select function(“unlock")
«offstage actor»
prompt for the key
enter key
verify key
signal: valid key, lock open
open the lock,
turn on the light
start ("duration“)
System Sequence Diagrams considered interactions between the actors
3
Design: Object Interactions
Design
Sequence Diagram
System Sequence Diagram
Controller
«initiating actor»
select function(“unlock")
: KeyStorage
: LockCtrl
checkKey()
ystem
: System
User
: Checker
Timer
sk := getNext()
«offstage actor»
prompt for the key
alt
enter key
val != null
setOpen(true)
verify key
signal: valid key, lock open
open the lock,
turn on the light
[else]
val == null : setLit(true)
start ("duration“)
• System Sequence Diagrams considered interactions between the actors
• Object Sequence Diagrams consider interactions between the objects
4
Metaphor for Software Design:
“Connecting the Dots”
Resident
:InterfacePage
:SearchRequest
:Controller
:PageMaker
:DatabaseConn
:Archiver
:Notifier
:InvestigRequest
We start with objects/concepts from the Domain Model
and modify or introduce new objects, as needed to
make the system function work.
Database
Landlord
5
Types of Object Responsibilities
• Knowing responsibility: Memorizing data or
references, such as data values, data
collections, or references to other objects,
represented as a property
• Doing responsibility: Performing computations,
such as data processing, control of physical
devices, etc., represented as a method
• Communicating responsibility: Communicating
with other objects, represented as message
sending (method invocation)
6
How To “Connect the Dots”
Starting Points:
Domain Model from UC-1 (domain concepts):
Symbolizes
“worker”-type
concept.
Use Case UC-1:
Unlock (flow of events):
1. User enters the key code
2. System verifies that the key is valid
3. System signals the key validity
4. System signals:
(a) to LockDevice to disarm the lock
(b) to LightSwitch to turn the light on
«entity»
KeyChecker
«boundary»
KeycodeEntry
«boundary»
StatusDisplay
Symbolizes
“thing”-type
concept.
«entity»
KeyStorage
«entity»
Key
«control»
Controller
LockDevice
«boundary»
HouseholdDeviceOperator
Scenario Walkthrough:
User
LightSwitch
for mapping a Use Case scenario to the Domain Model
Q: who handles this data?
Interface objects and Controller
message: checkKey(k)
Q: who performs the verification? Based on what data?
return value
Key Checker, based on entered key-code and stored valid keys
message: ???
Q: who signals? Based on what data?
Controller and Interface objects, based on key verification; because they are «boundary»
Q: who signals? Based on what data?
Controller or Key checker ???, based on key verification
Design: Assigning
Responsibilities
?
: DatabaseConn
?
: PageMaker
accessList := retrieve(params : string)
: Controller
: Checker
: DeviceCtrl
checkKey()
R1.
interfacePage :=
render(accessList : string)
?
activate( "lock" )
R2.
(a)
(b)
8
How Data Travels
Option A:
“expert” (Key Checker) passes the information (key validity) to another object (Controller)
which uses it to perform some work (activate the lock device)
key-code
key-code
Controller
is-valid
Checker
activation-params
Controller
LockCtrl
“expert” on key validity
Option B:
“expert” (Key Checker) directly uses the information (key validity)
to perform some work (activate the lock device)
key-code
key-code
Controller
activation-params
Checker
Advantage:
Shorter communication chain
LockCtrl
Drawback:
Extra responsibility for Checker
“expert” on key validity
Characteristics of Good Designs
• Short communication chains between the
objects
• Balanced workload across the objects
method_1()
method_1()
method_2()
…
method_N()
• Low degree of connectivity (associations)
among the objects
10
Design Principles
• Expert Doer Principle: that who knows should
do the task
• High Cohesion Principle: do not take on too
many computation responsibilities
• Low Coupling Principle: do not take on too many
communication responsibilities
There are many more …
11
Design: Assigning
Responsibilities
: Controller
: Checker
: DevCtrl
checkKey()
: Controller
: Checker
: DevCtrl
ok := checkKey()
?
(a)
setOpen(true)
setOpen(true)
(b)
• Although the Checker is the first to acquire the information about the key validity,
we decide to assign the responsibility to notify the LockCtrl to the Controller.
• This is because the Controller would need to know this information anyway—to
inform the user about the outcome of the key validity checking.
• In this way we maintain the Checker focused on its specialty and avoid assigning too
many responsibilities to it.
12
Cohesion
Low cohesion
High cohesion
13
Responsibility-Driven Design
1. Identify the responsibilities
•
•
domain modeling provides a starting point
some will be missed at first and identified in subsequent iterations
2. For each responsibility, identify the alternative
assignments
– if the choice appears to be unique then move to the next
responsibility
3. Consider the merits and tradeoffs of each alternative
by applying the design principles
– select what you consider the “optimal” choice
4. Document the process by which you arrived to each
responsibility assignment
14
UC-4: View Access Log
Resident
«html»
interfacePage :
specify
query
request
: Controller
: PageMaker
: DatabaseConnection
Database
get( queryRequest : string )
accessList := retrieve(params : string)
retrieve records
result
interfacePage := render(accessList : string)
alt
accessList != NULL
page :=
renderList()
[else]
result
displayed
page :=
warning()
«post page»
15
Example …
Communicating responsibilities identified for the system function “enter key”:
Responsibility Description
Send message to Key Checker to validate the key entered by the user.
Send message to DeviceCtrl to disarm the lock device.
Send message to DeviceCtrl to switch the light bulb on.
Send message to PhotoObserver to report whether daylight is sensed.
Send message to DeviceCtrl to sound the alarm bell.
16
Unlocking Sequence Diagram
: Controller
: Checker
: KeyStorage
: LockCtrl
: LightCtrl
: Logger
checkKey()
sk := getNext()
alt
val != null
[else]
setOpen(true)
val == null : setLit(true)
logTransaction(val)
sk = stored key; the process either terminates by matching a stored key or
exhausting the key store.
Key is a dynamic object, unlike others which are static contains keycode, name,
other forms of ID, timestamp, door ID, … -- disposed of after checking
17
Unlock Use Case
: Controller
enterKey()
k : Key
: Checker
: KeyStorage
: DeviceCtrl
: PhotoObsrv
: Logger
«create»
val := checkKey( k )
loop
[for all stored keys]
sk := getNext()
compare(k, sk)
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"
18
Unlock Seq. Diag. Variation 1
: Controller
k : Key
: Checker
: KeyStorage
: LockCtrl
k := create()
checkKey(k)
loop
sk := getNext()
setValid(ok)
controlLock(k)
ok := isValid()
opt
ok == true
setOpen(true)
To avoid an impression that the above design is the only one possible!!
Sets a boolean attribute of the Key object: ok = true/false;
Business logic (IF-THEN rule) relocated from Controller to LockCtrl
19
Unlock Seq. Diag. Variations 2&3
: LightCtrl
: PhotoSObs
controlLight()
: LightCtrl
checkIfDaylightAndIfNotThenSetLit()
dl := isDaylight()
opt
: PhotoSObs
dl == false
setLit(true)
dl := isDaylight()
The caller
could be
Controller or
KeyChecker
opt
dl == false
setLit(true)
Depends on which solution you consider more elegant;
It is helpful that checkIfDaylightAndIfNotThenSetLit() is named informatively (reveals the
intention), but the knowledge encoded in the name of the method is imparted onto the caller.
20
Summary of Design Variations
: Controller
enterKey()
k : Key
: Checker
: KeyStorage
: DeviceCtrl
: PhotoObsrv
: Logger
c
k := create()
val := checkKey(k)
loop
: DeviceCtrl
: PhotoSObs
[for all stored keys]
sk := getNext()
compare()
activate( "light" )
dl := isDaylight()
logTransaction(k, val)
«destroy»
alt
val == true
activate(“lock”)
opt
dl := isDaylight()
a
: Controller
opt
k : Key
[else]
prompt:
"try again"
dl == false
: Checker
numOfTrials++
dl == false
setLit(true)
activate(“bulb”)
: KeyStorage
: DeviceCtrl
k := create()
opt
checkKey(k)
numOfTrials == maxNumOfTrials
activate(“alarm”)
loop
b
sk := getNext()
: DeviceCtrl
: PhotoSObs
setValid(ok)
checkIfDaylightAndIfNotThenSetLit()
dl := isDaylight()
controlLock(k)
ok := isValid()
opt
ok == true
setOpen(true)
The caller
could be
Controller or
Checker
opt
dl == false
setLit(true)
21
Are We Done w/ UC-1: Unlock ?
• Didn’t check that the user is at the right door
– Missing: Managing access rights
• Didn’t distinguish critical and non-critical functions
– For example, what if logTransaction() call to Logger does not
return, e.g., no access to database (network outage) or disk-space
full ?
– Missing: Independent execution of non-critical functions
• Adding new household devices causes major design
changes
• Business rules are interleaved with authentication and
device management, but business rules are most likely
to change
• Etc.
Business Policies
IF key  ValidKeys THEN disarm lock and turn lights on
ELSE
increment failed-attempts-counter
IF failed-attempts-counter equals maximum number allowed
THEN block further attempts and raise alarm
Should be moved into a separate object:
• Make them explicit part of the model
• Confine the future changes in business policies
23
Class Diagram
Base Class
Container
PhotoSObsrv
Key
– code_ : string
– timestamp_ : long
– doorLocation_ : string
+ isDaylight() : boolean
1
sensor
1..*
KeyStorage
1
+ getNext() : Key
validKeys
1
Controller
# numOfAttemps_ : long
# maxNumOfAttempts_ : long
+ enterKey(k : Key)
– denyMoreAttempts()
1
1
1
logger
Logger
+ logTransaction(k : Key)
devCtrl
KeyChecker
checker + checkKey(k : Key) : boolean
– compare(k : Key, sk : Key) : boolean
DeviceCtrl
# devStatuses_ : Vector
+ activate(dev : string) : boolean
+ deactivate(dev :string) : boolean
+ getStatus(dev : string) : Object
24
Traceability Matrix (3)
Mapping: Domain model to Class diagram
Controller-SS1
StatusDisplay
Key
KeyStorage
KeyChecker
HouseholdDeviceOperator
IlluminationDetector
Controller-SS2
SearchRequest
InterfacePage
PageMaker
Archiver
DatabaseConnection
Notifier
InvestigationRequest
DatabaseConnection
PageMaker
«html» interfacePage
SearchRequest
Controller-SS2
Logger
PhotoSObsrv
DeviceCtrl
KeyChecker
KeyStorage
Key
Domain Concepts
Controller-SS1
Software Classes
X
X
X
X
X
X
X
X
X
X
X
25
Types of Object Communication
S1
A
A
B
B
S2
P
SN
(a)
(b)
(c)
26
Download