Title: Software Design Principles
1Software Design Principles
2Software design principles
- The single-responsibility principle
- The open-closed principle
- The Liskov substitution principle
- The dependency inversion principle
- The interface segregation principle
3The single-responsibility principle
- A class should have only one reason to change.
-- Robert Martin - A responsibility a reason to change
- Separate coupled responsibilities into separate
classes
4The single-responsibility principle
- Example
- Often we need to sort students by their name, or
ssn. So one may make Class Student implement the
Java Comparable interface. - class Student implements Comparable
-
- int compareTo(Object o)
-
-
- Student is a business entity, it does not know in
what order it should be sorted since the order of
sorting is imposed by the client of Student. - Worse every time students need to be ordered
differently, we have to recompile Student and all
its client. - Cause of the problems we bundled two separate
responsibilities (i.e., student as a business
entity with ordering) into one class a
violation of SRP
5The single-responsibility principle
Register Add(Course d, Student s)
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.
It invokes Collections.sort(aListofStudents)
6The single-responsibility principle
The solution is to separate the two
responsibilities into two separate classes and
use another version of Collections.sort().
It invokes Collections.sort(aListofStudents,
StudentBySSN)
7The single-responsibility principle
Computational Geometry Application
Graphical Application
GUI
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.
8The single-responsibility principle
Computational Geometry Application
Graphical Application
Graphic Rectangle draw()void
Geometric Rectangle area()double
GUI
- 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.
9The single-responsibility principle
Computational Geometry Application
Graphical Application
Rectangle -double length -double
width getLength()dobule getWidth()dobule
Graphic Rectangle draw()void
Geometric Rectangle area()double
GUI
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.
10The open-closed principle
- Software entities (classes, modules, functions,
etc,) should be open for extension, but closed
for modification. R. Martin - To make a class open for extension, closed for
modification, program the class to interfaces (or
abstract classes), not implementation (concrete
classes).
11The open-closed principle
Employee int EmpType
Faculty getOffice()
Staff getDept()
Secretary getTypeSpeed()
Engineer getEngTYpe()
void printEmpRoster(Employee emps) for
(int i iltemps.size() i) if
(empsi.empType FACULTY)
printfFaculty((Faculty)empsi) else
if (empsi.empType STAFF)
printStaff((Staff)empsi) else if
(empsi.empType SECRETARY)
printSecretary((Secretary)empsi)
What if we need to add Engineer??
12The open-closed principle
Employee printInfo()
Faculty printInfo()
Staff printInfo()
Secretary printInfo
Engineer printInfo()
void printEmpRoster(Employee emps) for
(int i iltemps.size() i)
empsi.printInfo()
When Engineer is added, printEmpRoster() does not
even need to recompile. PrintEmpRoster() is open
to extension, closed for modification.
13The open-closed principle
- Three versions of SORT
- sort(List list)
- Elements of list must implement Comparable
interface - sort(List list, StringComparator sc)
- Elements of list are not required to implement
Comparable - StringComparator orders objects of String only
- Sort(List list, Comparator comp)
- Elements of list are not required to implement
Comparable - Comparator may compare objects of any type.
- Open to extension since it can sort objects of
any type at any order specified in the second
parameter.
14The Liskov substitution principle
- Subtypes must be substitutable for their base
types. R. Martin - Demand no more, promise no less
- Demand no more the subclass would accept any
arguments that the superclass would accept. - Promise no less Any assumption that is valid
when the superclass is used must be valid when
the subclass is used. - Interface inheritance The LSP should be
conformed to. - Implementation inheritance use composition
instead of inheritance (in Java) or use private
base classes (in C).
15The Liskov substitution principle
- Implementation inheritance
- When you use List to implement Queue (in Java),
use composition, not inheritance. - The intention is that you use only Lists
implementation
ltfoundationgt List insert() delete() find()
List insert() delete() find()
List insert() delete() find()
MyList
Queue enqueue() dequeue() isEmpty()
Queue enqueue() dequeue() isEmpty()
Queue enqueue() dequeue() isEmpty()
16The Liskov substitution principle
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?
Rectangle -int width -int height getWidth() set
Width() getHeight() setHeight() area()
IS-A
Square getWidth() setWidth() getHeight() setHe
ight()
17The Liskov substitution principle
- Rectangle and Square
- Invariant of Rectangle width and height are
independent of each other (which can be expected
from the setWidth and setHeight operations) - Square violates the width-height-independence
invariant of Rectangle
18The Liskov substitution principle
- There are cases in which the substitutability may
not be needed - Generalization we found that Faculty, Staff,
Secretary and Engineer all have the same set of
attributes and operations, so we created the
Employee as a placeholder for those common
properties. - For the system, there is no client for Employee
- Thus, the four subclasses do not need to be
substitutable - Actually, there is no way we can tell whether
they are or not.
Employee printInfo()
Faculty printInfo()
Staff printInfo()
Secretary printInfo
Engineer printInfo()
generalization
19The dependency inversion principle
- Abstraction should not depend on details.
Details should depend on abstraction. R.
Martin - High-level concepts are more stable than
low-level implementation
20The dependency inversion principle
Policy Layer
High-level modules make calls to low-level
modules.
Mechanism Layer
Utility Layer
The upper-level layer is dependent upon
lower-level layers.
21The dependency inversion principle
Dependency Inversion Lower-level layers is
dependent upon upper-level layers.
Policy
Policy Layer
Mechanism
Mechanism Layer
ltltinterfacegtgt Policy Service
Utility
ltltinterfacegtgt Mechanism Service
Utility Layer
Ownership Inversion The client (upper-level
layer) owns the interface, not the lower-level
layers
22The interface segregation principle
- Clients should not be forced to depend on
methods that they do not use. R. Martin - When we bundle functions for different clients
into one interface/class, we create unnecessary
coupling among the clients. - When one client causes the interface to change,
all other clients are forced to recompile.
23Software design principles - summary
- The single-responsibility principle
- There is only one source that may the class to
change - The open-closed principle
- Open to extension, closed for modification
- The Liskov substitution principle
- A subclass must substitutable for its base class
- The dependency inversion principle
- Low-level (implementation, utility) classes
should be dependent on high-level (conceptual,
policy) classes - The interface segregation principle
- A client should not be forced to depend on
methods it does not use.