Transcript OO Design
OO Design
by
V. Mukhortov
Novosoft, 2001
1
OO Design Goals
Flexibility
Changes must be localized
Maintainability
Modules requiring changes can be easily identified and
changes can be made at their place and cost
Reusability
Modules should be able to be used in other contexts
2
OO Designer Activities
Class design
Package design
Describing the design patterns
3
Class design principles
ORR
LSP
LoD
OCP
ISP
One Responsibility Rule
Liskov Substitution Principle
Law of Demeter
Open-Closed Principle
Interface Segregation Principle
4
ORR - One Responsibility Rule
A class has a single responsibility:
it does it all,
it does it well,
it does it only
- R. Martin
5
LSP – Liskov Substitution Principle
Functions that use pointers or references to base classes must
be able to use objects of the derived classes without knowing it.
- R.Martin, 1996
Original formula:
If for each object o1 of type S there is an object o2 of type T
such that for all programs P defined in terms of T the behavior
of P is unchanged when o1 is substituted by o2 then S is a
subtype of T.
- Barbara Liskov, 1988
6
LSP violation: Rectangle & Square
class Rectangle
{
private int h;
private int w;
public Rectangle( int w, int h )
{ this.h = h; this.w = w; }
public void setHeight( int h ) { this.h = h; }
public int getHeight()
{ return h; }
}
class Square extends Rectangle
{
public Square( int s ) { super( s, s ); }
}
Problem:
Square s = new Square(5);
s.setHeight(6); // s is not consistent
7
class Square extends Rectangle
{
public Square( int s ) { super( s, s ); }
public void setSize( int s ) {
super.setHeight(s); super.setWidth(s);
}
public void setHeight( int h ) { setSize(h); }
public void setWidth( int w ) { setSize(w); }
}
Problem:
void f( Rectangle r ) throws Exception {
r.setHeight(4);
r.setWidth(5);
if( r.getHight() * r.getWidth() != 20 ) throw new Exception( “Bug!” );
}
8
LSP: The real problem
•
•
•
•
?
Square object is not a Rectangle object!
Why?
Because of behavior of a Square is not
consistent with the behavior of a Rectangle!
• and …
• it is behavior that software is really all about!
IsA is a behavioral relationship.
9
LoD – Law of Demeter
A method should have limited knowledge of an object model.
- D. Rumbaugh
Original formula: Only talk to your immediate friends.
- Ian Holland, 1987
immediate friends of method f :
• methods of class of f and other argument classes of f
• methods of immediate part classes of class of f
• methods of classes of objects that are created in f .
10
Booch about The LoD
“The basic effect of applying this Law is the creation of
loosely coupled classes, whose implementation secrets are
encapsulated. Such classes are fairly unencumbered, meaning
that to understand the meaning of one class, you need not
understand the details of many other classes.”
11
LoD violation
Problem: public void getTimeOfBirth() {
long time = p.getDateOfBirth().getTime();
}
Do not reveal a class secret!
12
LoD-compliant design
Solution:
void m() { this.b.call_foo(); } // hide the class secret!
13
OCP – Open-Closed Principle
Software entities (classes, modules, functions, etc) should be
open for extension, but closed for modification.
- B. Meyer, 1988
14
OCP violation: Shapes
void drawShapes( Shape[] shapes )
{
for( int i = 0; i < shapes.length; ++i )
{
if( shape[i].getType == Shape.SQUARE )
{
drawSquare( (Square)shape[i] );
}
else drawCircle( (Circle)shape[i] );
}
}
The problem:
You can't add a new shape without changing drawShapes() code.
15
OCP compliant solution
void drawShapes( Shape[] shapes )
{
for( int i=0; i < shapes.length; ++i )
{
shape[i].draw( device );
}
}
16
ISP – Interface Segregation Principle
Clients should not be forced to depend upon services they
do not use.
- R.Martin, 1996
Hints:
Avoid fat interfaces
Separate clients mean separate interfaces
Violation cost:
lack of flexibility
17
ISP violation: Security Door
Door has to sound an alarm if it is open for too long.
Problem:
Timeout method has to be public.
But…there are Door clients that do NOT use timeout method
and don’t have to. This approach leads to mistakes.
18
ISP-compliant Security Door
Door clients still can use TimedDoor via Door interface
Door clients will not be affected by changes made in Timer,
TimerClient and TimedDoor
19
ISP violation: ATM Transactions
Adding new transactions causes all other transactions to
recompile
If any Transaction requires a change to UI, all of the other will
be forced to recompile
20
ISP-compliant solution
21
Dependencies
MDP
DIP
ADP
Minimal Dependencies Principle
Dependency Inversion Principle
Acyclic Dependencies Principle
22
DIP – Dependency Inversion Principle
High level modules should not depend upon low-level ones.
Both should depend upon abstractions.
Abstractions should not depend upon implementation details.
Details should depend upon abstractions.
- R.Martin, 1996
23
DIP violation: Copier
What if we need to support another kind of printer ?
24
DIP-compliant solution
Now we can easily add new writers and readers
25
ADP – Acyclic Dependencies
Principle
The dependency structure between entities (classes, packages,
functions) must be a Directed Acyclic Graph (DAG).
- R.Martin, 1996
Two entities having to know about each other can not be used
separately. They work like a monolith and there is no benefit in
separating them.
Increases maintainability
26
Example: cyclic dependencies
Application
MyTasks
MyDialogs
TaskWindow
MessageWindow
Task
Windows
Due to the dependency from MyDialogs to Application,
MyTasks package depends upon the entire system.
27
Package design principles
CCP - Common Closure Principle
REP - Reuse-Release Equivalence Principle
CRP - Common Reuse Principle
SDP - Stable Dependencies Principle
SAP - Stable Abstractions Principle
28
CCP – Common Closure
Principle
Classes within the package should be affected by the same
kind of changes. Either all open to the kind of change or all
closed to the kind of change.
- R.Martin, 1996
Produces packages where changes are very localized, and,
therefore, number of releases is minimized.
29
REP - Reuse/Release
Equivalence Principle
The unit of reuse is the unit of release. The unit is what UML
refers to as a package.
- R.Martin, 1996
Classes should be grouped into packages according to how
they will be reused
To be effectively reused, packages must be given a release
number
Makes updates convinient for reusers
30
CRP – Common Reuse Principle
The classes in a package are to be reused together. Reusers
should depend upon the entire package, not just a part of it.
- R.Martin, 1996
ISP, scaled to packages
Reduces maintenance cost, increases reusability
Another Package
My Package
class i'm
using
class I'm
NOT using
31
CRP violation: remote service
Service
Application
ServiceAgent
(from Service)
ServiceImpl
(from Service)
Service
Main
ServiceException
ServiceServer
(from Service)
(from Service)
Problem: Every time the new version of Service is released,
clients of ServiceAgent must expect that their code won’t work,
even if changes do not affect ServiceAgent.
32
CRP compliant design
agent
service
ServiceAgent
Service
server
ServiceServer
application
local
Main
ServiceImpl
Clients of ServiceAgent depend only upon things they really use.
Benefit: Application can easily switch from local to remote
service implementation.
33
CRP compliant design
agent
service
ServiceAgent
Service
Exception
server
ServiceServer
application
Main
local
ServiceImpl
Callback
Clients of ServiceAgent depend only upon things they really use.
Benefit: Changes in local and server packages do not affect
application
34
SDP - Stable Dependencies
Principle
A package should only depend upon packages that are more
stable than itself.
Stability is a measure of difficulty in changing a package.
- R.Martin, 1996
What makes a package hard to change?
Increases maintainability
35
Instability Definition
Instability of a package
I = Ce / ( Ca + Ce )
where
Ce =
efferent couplings (number of classes inside the
package that depend upon classes outside the
package )
Ca = afferent couplings (number of classes outside the
package that depend upon classes within the
package)
36
SAP – Stable Abstractions
Principle
The abstractness of the package should be proportional to its
stability.
- R.Martin, 1996
If all packages are maximally stable, the system would be
unchangable .
Therefore, some packages must be instable.
Increases maintainability
37
Abstractness Definition
Abstractness of a package
A = Na / N
where
Na = number of abstract classes
N = total number of classes
38
Main sequence
Main Sequence – an instability versus abstractness graph
Packages along the line from (0,1) to (1,0) have a good
balance
Distance from the main sequence
D=|A+I –1|
Given this metric, a design can be analyzed for its overall
conformance to the main sequence.
- R.Martin, 1994
39
Main sequence
I
1
USELESS
AREA
CONCRETE
CLASSES
0
A
1
40
Example: server
I=0 A=1 D=0
AbstractServer
Client
Server
ResultSet
Code
I=2/3 A=0 D=1/3
I = 1/1 = 1
A= 0
D= 0
MyServer
SomeServer
SomeResultSet
What happens if ResultSet is not an interface?
41
Example: server
I=0 A=1/2 D=1/2
AbstractServer
ResultSet
Client
Server
Code
I=1 A=0 D=0
MyServer
SomeServer
I=1/2 A=0 D=1/2
This change affects both MyServer and AbstractServer balance
42