software design principles august 19, 2005. software design principles the single-responsibility...

23
Software Design Software Design Principles Principles August 19, 2005 August 19, 2005

Upload: dwayne-denis-cobb

Post on 26-Dec-2015

217 views

Category:

Documents


1 download

TRANSCRIPT

Software Design Software Design PrinciplesPrinciples

August 19, 2005August 19, 2005

Software design principlesSoftware design principles

The single-responsibility principleThe single-responsibility principle The open-closed principle The open-closed principle The Liskov substitution principleThe Liskov substitution principle The dependency inversion The dependency inversion

principleprinciple The interface segregation The interface segregation

principleprinciple

The single-responsibility principleThe single-responsibility principle

““A class should have only one A class should have only one reason to change.” -- Robert reason to change.” -- Robert MartinMartin

A responsibility = a reason to A responsibility = a reason to changechange

Separate coupled responsibilities Separate coupled responsibilities into separate classesinto separate classes

The single-responsibility principleThe single-responsibility principle

Example: Example: – Often we need to sort students by their name, or Often we need to sort students by their name, or

ssn. So one may make Class Student implement ssn. So one may make Class Student implement the Java Comparable interface.the Java Comparable interface.

class Student implements Comparable {class Student implements Comparable {……int compareTo(Object o) { … }int compareTo(Object o) { … }……

};};– Student is a business entity, it does not know in Student is a business entity, it does not know in

what order it should be sorted since the order of what order it should be sorted since the order of sorting is imposed by the client of Student.sorting is imposed by the client of Student.

– Worse: every time students need to be ordered Worse: every time students need to be ordered differently, we have to recompile Student and all differently, we have to recompile Student and all its client.its client.

– Cause of the problems: we bundled two separate Cause of the problems: we bundled two separate responsibilities (i.e., student as a business entity responsibilities (i.e., student as a business entity with ordering) into one class – a violation of SRPwith ordering) into one class – a violation of SRP

The single-responsibility The single-responsibility principleprinciple

AClientop() { ;}

RegisterAdd(Course d, Student

s);

Comparable

int compareTo()

StudentSSN

NamegetSSN()

getName()major

getMajor()int compareTo()

It invokesCollections.sort(aListofStudents);

When a new requirement needs to sort students in a different order, Student, Register, and AClient all need to be recompiled, even Register has nothing to do with any ordering of Students.

The single-responsibility The single-responsibility principleprinciple

ClientAop() { ;}

RegisterAdd(Course d, Student

s);Comparator

int compare(Object o1, Object o2)

StudentSSN

NamegetSSN()

getName()major

getMajor()

It invokesCollections.sort(aListofStudents, StudentBySSN);

The solution is to separate the two responsibilities into two separate classes and use another version of Collections.sort().

StudentByNameint compare(Object o1, Object

o2)

StudentBySSNint compare(Object o1, Object

o2)

ClientBop() { ;}

The single-responsibility The single-responsibility principleprinciple

GUI

Computational

GeometryApplication

Rectangle

+draw():void+area():integer

Class Rectangle may be forced to make changes from two different unrelated sources. One is from the Computational Geometry Application (CGA). E.g., adding area function for length and width of type double. The other is from Graphical Application (GA). E.g., add draw() in Windows XP to the existing draw in X Windows. A change from either of the two source would still cause the other application to recompile.

GraphicalApplication

The single-responsibility The single-responsibility principleprinciple

GUI

Computational

GeometryApplication

GraphicRectangle

+draw():void

GraphicalApplication

GeometricRectangle

+area():double

• Package CGA is no longer dependent on graphical side of Rectangle and thus it becomes independent of package GUI. Any change caused by graphical application no longer requires CGA to be recompiled.• However, any changes from the CGA side may cause GA to be recompiled.

The single-responsibility The single-responsibility principleprinciple

GUI

Computational

GeometryApplication

GraphicRectangle

+draw():void

GraphicalApplication

GeometricRectangle

+area():double

Rectangle-double length-double width+getLength():dobule+getWidth():dobule

Class Rectangle contains the most primitive attributes and operations of rectangles. Classes GeometricRectangle and GraphicRectangle are independent of each other. A change from either side of CGA or GA, it would not cause the other side to be recompiled. NOTE: this does not violate LSP, since Rectangle does not have any client.

The open-closed principleThe open-closed principle

““Software entities (classes, modules, Software entities (classes, modules, functions, etc,) should be functions, etc,) should be open for open for extensionextension, but , but closed for closed for modificationmodification.” – R. Martin.” – R. Martin

To make a class open for extension, To make a class open for extension, closed for modification, program the closed for modification, program the class to interfaces (or abstract class to interfaces (or abstract classes), not implementation classes), not implementation (concrete classes).(concrete classes).

The open-closed principleThe open-closed principle

Employee+int EmpType

Faculty+getOffice()

void printEmpRoster(Employee[] emps) { for (int i; i<emps.size(); i++) { if (emps[i].empType == FACULTY) printfFaculty((Faculty)emps[i]); else if (emps[i].empType ==STAFF) printStaff((Staff)emps[i]); else if (emps[i].empType == SECRETARY) printSecretary((Secretary)emps[i]); }}

Staff+getDept()

Secretary+getTypeSpeed()

Engineer+getEngTYpe()

What if we need to add Engineer??

The open-closed principleThe open-closed principle

Employee+printInfo()

Faculty+printInfo()

void printEmpRoster(Employee[] emps) { for (int i; i<emps.size(); i++) { emps[i].printInfo(); }}

Staff+printInfo()

Secretary+printInfo

Engineer+printInfo()

When Engineer is added, printEmpRoster() does not even need to recompile. PrintEmpRoster() is open to extension, closed for modification.

The open-closed principleThe open-closed principle

Three versions of SORTThree versions of SORT– sort(List list)sort(List list)

Elements of list must implement Elements of list must implement ComparableComparable interfaceinterface

– sort(List list, StringComparator sc)sort(List list, StringComparator sc) Elements of list are not required to implement Elements of list are not required to implement

ComparableComparable StringComparator orders objects of String onlyStringComparator orders objects of String only

– Sort(List list, Comparator comp)Sort(List list, Comparator comp) Elements of list are not required to implement Elements of list are not required to implement

ComparableComparable ComparatorComparator may compare objects of any type. may compare objects of any type. Open to extension since it can sort objects of any Open to extension since it can sort objects of any

type at any order specified in the second type at any order specified in the second parameter.parameter.

The Liskov substitution principleThe Liskov substitution principle

““Subtypes must be substitutable for their Subtypes must be substitutable for their base types.” – R. Martinbase types.” – R. Martin

Demand no more, promise no lessDemand no more, promise no less– Demand no moreDemand no more: the subclass would accept any : the subclass would accept any

arguments that the superclass would accept.arguments that the superclass would accept.– Promise no lessPromise no less: Any assumption that is valid when : Any assumption that is valid when

the superclass is used must be valid when the the superclass is used must be valid when the subclass is used.subclass is used.

Interface inheritanceInterface inheritance – The LSP should be – The LSP should be conformed to.conformed to.

Implementation inheritanceImplementation inheritance – use – use composition instead of inheritance (in Java) composition instead of inheritance (in Java) or use private base classes (in C++).or use private base classes (in C++).

The Liskov substitution principleThe Liskov substitution principle

Implementation inheritanceImplementation inheritance – When you use List to When you use List to implementimplement Queue (in Java), use Queue (in Java), use

composition, not inheritance.composition, not inheritance.– The intention is that you use only List’s implementationThe intention is that you use only List’s implementation

List+insert()+delete()+find()

Queue+enqueue()+dequeue()+isEmpty()

<foundation>

List+insert()+delete()+find()

Queue+enqueue()+dequeue()+isEmpty()

List+insert()+delete()+find()

Queue+enqueue()+dequeue()+isEmpty()

MyList

The Liskov substitution principleThe Liskov substitution principle

Rectangle-int width;-int height+getWidth()+setWidth()+getHeight()+setHeight()+area();

class Square extends Rectangle { public void setWidth(int width) { super.setWidth(width); super.setHeight(width); } public void setHeight(int height) { super.setHeight(height); super.setWidth(height); }}void clientOfRectangle(Rectangle r) { r.setWidth(10); r.setHeight(20); print(r.area());}Rectangle r = new Square(…);clientOfRectangle(r); // what would be printed?

Square+getWidth()+setWidth()+getHeight()+setHeight()

IS-A

The Liskov substitution principleThe Liskov substitution principle

Rectangle and SquareRectangle and Square– Invariant of Rectangle: width and Invariant of Rectangle: width and

height are independent of each height are independent of each other (which can be expected from other (which can be expected from the setWidth and setHeight the setWidth and setHeight operations)operations)

– Square violates the width-height-Square violates the width-height-independence invariant of Rectangleindependence invariant of Rectangle

The Liskov substitution The Liskov substitution principleprinciple

Employee+printInfo()

Faculty+printInfo()

Staff+printInfo()

Secretary+printInfo

Engineer+printInfo()

There are cases in which There are cases in which the substitutability may not be the substitutability may not be neededneeded

Specialization: we found that Faculty, Staff, Secretary Specialization: we found that Faculty, Staff, Secretary and Engineer all have the same set of attributes and and Engineer all have the same set of attributes and operations, so we created the Employee as a operations, so we created the Employee as a placeholderplaceholder for those common properties. for those common properties.

For the system, there is no client for EmployeeFor the system, there is no client for Employee Thus, the four subclasses do not need to be Thus, the four subclasses do not need to be

substitutablesubstitutable Actually, there is no way we can tell whether they are or Actually, there is no way we can tell whether they are or

not. not.

Specialization

The dependency inversion The dependency inversion principleprinciple

““Abstraction should not depend Abstraction should not depend on details. Details should depend on details. Details should depend on abstraction.” – R. Martinon abstraction.” – R. Martin

High-level concepts are more High-level concepts are more stable than low-level stable than low-level implementationimplementation

The dependency inversion The dependency inversion principleprinciple

Policy Layer

Mechanism Layer

Utility LayerThe upper-level layer is

dependent upon lower-level layers.

High-level modules make calls to low-level modules.

The dependency inversion The dependency inversion principleprinciple

Policy

Policy Layer

<<interface>>

PolicyService

Mechanism

Mechanism Layer

<<interface>>

MechanismService

Utility

UtilityLayer

Dependency Inversion: Lower-level layers is dependent upon upper-level

layers.

Ownership Inversion: The client (upper-level layer) owns the interface, not the lower-level

layers

The interface segregation The interface segregation principleprinciple

““Clients should not be forced to Clients should not be forced to depend on methods that they do depend on methods that they do not use.” – R. Martin not use.” – R. Martin

When we bundle functions for When we bundle functions for different clients into one different clients into one interface/class, we create interface/class, we create unnecessary coupling among the unnecessary coupling among the clients.clients.– When one client causes the interface When one client causes the interface

to change, all other clients are forced to change, all other clients are forced to recompile.to recompile.

Software design principles - Software design principles - summarysummary

The single-responsibility principleThe single-responsibility principle– There is only one source that may the class to There is only one source that may the class to

changechange The open-closed principle The open-closed principle

– Open to extension, closed for modificationOpen to extension, closed for modification The Liskov substitution principleThe Liskov substitution principle

– A subclass must substitutable for its base classA subclass must substitutable for its base class The dependency inversion principleThe dependency inversion principle

– Low-level (implementation, utility) classes should be Low-level (implementation, utility) classes should be dependent on high-level (conceptual, policy) classesdependent on high-level (conceptual, policy) classes

The interface segregation principleThe interface segregation principle– A client should not be forced to depend on methods A client should not be forced to depend on methods

it does not use.it does not use.