Design Principles iwongu at gmail dot com. What is Object-Oriented design?
-
Upload
caroline-page -
Category
Documents
-
view
219 -
download
3
Transcript of Design Principles iwongu at gmail dot com. What is Object-Oriented design?
Design Principles
iwongu at gmail dot com
What is Object-Oriented design?
Dependency Management
First VersionAll designs start well
void copy(){
int ch;while ( (ch = ReadKeyboard()) != EOF)
WritePrinter(ch);}
Second VersionOh, no! Nobody said the requirements might change!
bool gTapeReader = false; // remember to reset this flag
void copy(){
int ch;while ( (ch = gTapeReader ? ReadTape() : ReadKeyboard()) != EOF)
WritePrinter(ch);}
Third VersionHow unexpected! Requirements changed again!
bool gTapeReader = false; bool gTapePunch = false;// remember to reset these flags
void copy(){
int ch;while ( (ch = gTapeReader ? ReadTape() : ReadKeyboard()) != EOF)
gTapePunch ? WritePunch(ch) : WritePrinter(ch);}
Won-derful
Use
Change
Rot
Smell
Re-design
Design SmellsThe odors of rotting software
1. It’s rigid.2. It’s fragile.3. It’s not reusable.
RigidityRigidity is the inability to be changed
1. The impact of a change cannot be predicted.
2. If not predicted, it can not be esti-mated.
3. Time and cost can not be qualified.4. Managers become reluctant to au-
thorize change.
FragilitySoftware changes seem to exhibit non-local effects.
1. A single change requires a cascade of subsequent changes.
2. New errors appear in areas that seem unconnected to the changed areas
3. Quality is unpredictable.4. The development team loses credi-
bility.
ImmobilityIt's not reusable.
1. Desirable parts of the design are dependent on undesirable parts.
2. The work and risk of extracting the desirable part may exceed the cost of redeveloping from scratch.
Example of a good designFirst and only version!
void copy(FILE* in, FILE* out){
int ch;while ( (ch = fgetc(in)) != EOF)
fputc (ch, out);}
But, wait! Aren't we supposed to be learning OO design? This isn't OO, is it?
… Is it?It's a small program based on abstraction!
1. FILE is an abstraction.a. It represented some kind of byte stream.b. It has many variations.
2. It has methods.a. The methods are dynamically bound.
FILE is a class, just implemented differ-ently.
Rephrased in OOFirst and only version!
interface Reader{ char read(); }
interface Writer{ void write(char c); }
public class Copy{
Copy(Reader r, Writer w){
itsReader = r;itsWriter = w;
}public void copy(){
int c;while ( (c = itsReader.read()) != EOF )
itsWriter.write(c);}
Reader itsReader;Writer itsWriter;
}
CHANGE
“CHANGE”
The one constant in software devel-opment
“Belady and Lehman’s Laws”
Software will continually change.
Software will become increasingly unstructured as it is changed.
Ities of Software Quality
• Reliability• Efficiency• Readability• Understandability• Modifiability, Maintainability• Testability• Portability
UMLUnified Modeling Language
Class
Customer
-name: String-address: String
+creditRating()
Association
Customer
-name: String-address: String
+creditRating()
Order
-dateReceived: Date-number: String-price: Money
+dispatch()+close()
1*
Generalization
Customer
-name: String-address: String
+creditRating()
Order
-dateReceived: Date-number: String-price: Money
+dispatch()+close()
Corporate Customer
-contactName: String-creditRating: String-creditLimit: Double
+remind()+billForMonth()
Personal Customer
-creditCard#: long int
1*
Dependency
Customer
-name: String-address: String
+creditRating()
Order
-dateReceived: Date-number: String-price: Money
+dispatch()+close()
Corporate Customer
-contactName: String-creditRating: String-creditLimit: Double
+remind()+billForMonth()
Personal Customer
-creditCard#: long int
Date
Money
1*
UML Class Diagram shows the relationships of Classes.
Dependency
Association
Aggregation
Composition
Generalization
Realization
Design Principles
Design Principles
SRP Single Responsibility Principle OCP Open Closed Principle LSP Liskov Substitution Principle DIP Dependency Inversion Principle ISP Interface Segregation Prin-
ciple
SRPSingle Responsibility Princi-
ple
There should never be more than one reason for a class
to change.
In the context of the SRP,a responsibility means "a
reason for change."
Each responsibility is an axis of change.
Orthogonalclass Y
class X
No need to change
Non-Orthogonalclass Y
class X
Need to change
SRP Violation
Rectangle
+draw()+area(): double
Computational Geometry Application Graphical Application
GUI
SRP
Computational Geometry Application
Graphical Application
GUI
Geometric Rectangle
+area(): double
Rectangle
+draw()
But, it’s not easy to see SRP.
Modem
+dial()+hangup()+send()+recv()
But, it’s not easy to see SRP.
Modem
+dial()+hangup()+send()+recv()
Data Channel<<interface>>
+send()+recv()
Connection<<interface>>
+dial()+hangup()
Question?
OCPOpen-Closed Principle
Software entities should be open for extension
but closed for modification.
But how?
Abstraction is the key.
enum ShapeType { circle, square }; struct Shape { ShapeType itsType; };
struct Circle { ShapeType itsType;
}; struct Square {
ShapeType itsType; };
void DrawAllShapes(Shape* list[], int n) { for (int i = 0; i < n; ++i) {
Shape* s = list[i]; switch (s->itsType) { case square:
DrawSquare((Square*)s); break;
case circle: DrawCircle((Circle*)s); break;
} }
}
struct Shape {virtual void Draw() const = 0;
};struct Square : Shape {
virtual void Draw() const;};struct Circle : Shape {
virtual void Draw() const;};
void DrawAllShapes(Shape* list[], int n) {for (int i = 0; i < n; ++i) {
Shape* s = list[i];s->Draw();
}}
OCP Violation
If new shapes are needed,
Square
Circle
ShapeDrawAllShapes
OCP Violation
Circle
Square
DrawAllShapes
Triangle
Pentagon
Shape
OCP
If new shapes are needed,
Circle Square
DrawAllShapes Shape
OCP
Circle Square
DrawAllShapes
Triangle Pentagon
Shape
But, OCP is not just inheri-tance.
OCP is the root motivationbehind many of the heuris-
tics and conventions.
For example,
Make All Member Variables Private.
No Global Variables – Ever.
RTTI is Dangerous.
Question?
LSPLiskov Substitution Principle
Subtypes should be substi-tutable for their base types.
Rectangle
Rectangle
-top_left: Point-width: double-height: double
+set_width(w: double)+set_height(h: double)+get_width(): double+get_height(): double
Square IS-A rectangle.
Square
Rectangle
-top_left: Point-width: double-height: double
+set_width(w: double)+set_height(h: double)+get_width(): double+get_height(): double
Square
void Square::set_width(double w){
Rectangle::set_width(w);Rectangle::set_height(w);
}
void Square::set_height(double h){
Rectangle::set_width(h);Rectangle::set_height(h);
}
double g(Rectangle& r){
r.set_width(5);r.set_height(4);
assert(r.area() == 20);}
Square IS-A rectangle.But,
Square is NOT substitutable for rectangle.
Violating the LSP often re-sults in the use of Run-Time
Type Information (RTTI).
double g(Rectangle& r){
r.set_width(5);r.set_height(4);
if (dynamic_cast<Square*>(&r) != 0){
assert(r.area() == 16);}else{
assert(r.area() == 20);}
}
It’s also a violation of OCP.
Rectangle
-top_left: Point-width: double-height: double
+set_width(w: double)+set_height(h: double)+get_width(): double+get_height(): double
Square
g
Using DBC, LSP means,
DBC?
Design By Contract.
PreconditionPostcondition
Invariant
A routine redeclaration may only replace the original
precondition by one equal or weaker, and the original postcondition by one equal
or stronger.
Base
Derived
The postcondition of Square::set_width() is
weaker than the postcondi-tion of
Rectangle::set_width().
Rectangle
Square
Question?
DIPDependency Inversion Prin-
ciple
a. High-level modules should not depend on low-level modules. Both should
depend on abstractios.
b. Abstractions should not depend on details. Details should depend on abstrac-
tions.
Structured Design
Policy Layer
Mechanism Layer
Utility Layer
Dependency Inversion
Policy Layer
Mechanism Layer
Utility Layer
Policy Service Interface<<interface>>
Mechanism Service Interface<<interface>>
Dependency Inversion
Utility
Mechanism
Policy
Policy Layer
Mechanism Layer
Utility Layer
Policy Service Interface<<interface>>
Mechanism Service Interface<<interface>>
Depend on abstractions.
No variable should hold a pointer or reference to a con-crete class.
No class should derive from a concrete class.
No method should override an implemented method of any of its base classes.
But, it’s impossible.
For example, someone has to create the instances of the concrete class, and
whatever module does that will depend on them.
And, it might not be a prob-lem to depend on concrete
but non-volitile classes.
DIP Violation
Button
+poll()
Lamp
+turn_on()+turn_off()
DIP
Button
+poll()
ButtonServer<<interface>>
+turn_on()+turn_off()
Lamp
Question?
ISPInterface Segregation Prin-
ciple
Door
And, we need a timed door.
Door<<interface>>
+lock()+unlock()+is_open()
Timer
Timer
+register()
TimerClient<<interface>>
+timeout()0..*
The first solution
What are problems?
Door<<interface>>
+lock()+unlock()+is_open()
Timer
+register()
TimerClient<<interface>>
+timeout()0..*
TimedDoor
Not all varieties of Door need timing.
Violation of LSP.
The interface of Door has been polluted with a
method that it does not re-quire.
Fat Interface.
ISPInterface Segregation Prin-
ciple
Clients should not be forced to depend on methods that
they do not use.
Multiple inheritance
Door<<interface>>
+lock()+unlock()+is_open()
Timer
+register()
TimerClient<<interface>>
+timeout()0..*
TimedDoor
Delegation
Door<<interface>>
+lock()+unlock()+is_open()
Timer
+register()
TimerClient<<interface>>
+timeout()0..*
TimedDoor
DoorTimer Adapter
Question?
References
http://objectmentor.com/http://objectmentor.com/resources/omi_reports_index.htmlhttp://objectmentor.com/resources/publishedArticles.html → Robert C. Martin