Sei sulla pagina 1di 26

COSC 2P90

OBJECT-ORIENTED PRINCIPLES

(c) S. Thompson 1
Software Architecture

 What is it?
 Highest Level: overall shape and structure of
software applications
 Next Level: Related to the purpose of the software
 Next Level: modules and their interconnection
 i.e. Design Patterns
 Classes
 Components
 Packages

http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf (c) S. Thompson 2


Design and Software

 What goes wrong with software?


 Even though software starts out clean and
elegant:
 Becomes difficult to extend
 Becomes difficult to maintain
 ‘Redesign’ is the proposed solution – usually fails!
 The design rots
 Wasn’t designed for change
 Difficult design to maintain
(c) S. Thompson 3
Symptoms of Rotting Designs

 Rigidity
 Changes to one module cause (unforeseen)
changes to other modules
 ‘Simple’ tasks take far longer than estimates
 Causes an aversion to change the software!
 Fragility
 Software breaks in many places each time it is
changed
 Often in times with no conceptual relationship
with the changed area

(c) S. Thompson 4
 Immobility
 Reuse of software from one project to another
becomes difficult
 Modules have ‘baggage’ that make it difficult to move
 Rewrite is then done instead of reuse
 Viscosity
 Of the design: viscosity is high when maintaining the
design is difficult
 Of the environment: proper change is difficult because
the development environment is slow or inefficient

(c) S. Thompson 5
Changing Requirements

 Software rot occurs when requirements


change in ways the software did not
anticipate
 Changes are made that violate the original
design
 Designs need to be resilient to change

(c) S. Thompson 6
O-O Class Design Principles

 Following principles can be employed in


designs to help prevent rot
1. The Open-Closed Principle
2. The Liskov Subtitution Principle
3. The Dependency-Inversion Principle
4. The Interface-Segregation Principle
5. The Single-Responsibility Principle

(c) S. Thompson 7
Open-Closed Principle

 A module should be open for extension but


closed for modification.
 We should write our modules so that they can
be extended, without requiring them to be
modified
 Change what the modules do, without changing
their source code
 If we don’t change code, we can’t break
 Several techniques exist to help enforce this
(c) S. Thompson 8
Open-Closed Principle

 Dynamic Polymorphism
 Rehash of Procedure vs OO
enum Shape {
Circle,
interface Shape {
Square,
Line
void draw();
}
...
}
void Draw( Shape s ) ...
{
switch (s) { void Draw( Shape s )
case Circle: drawCircle(); break;
case Square: drawSquare(); break; {
case Line: drawLine(); break;
} s.draw();
}
}

(c) S. Thompson 9
Open-Closed Principle

 Dynamic Polymorphism
 Without dynamic polymorphism, we are required
to edit Draw() to add a new shape.
 We can implement a new interface simply by
adding new code
 Nothing exists to make sure we have found all the
switch/if cases on shape
 An interface (or an abstract class) clearly defines
what needs to be added to extend the system

(c) S. Thompson 10
Open-Closed Principle

 Static Polymorphism
 i.e. Generics/Templates can be used to achieve this as
well
template <typename SHAPE>
void Draw( SHAPE s )
{
s.Draw();
}
 There is still an implicit interface used
 More difficult with generics than templates

(c) S. Thompson 11
Liskov Substitution
Principle
 Subclasses should be substitutable for their
base classes.
 This has been covered previously
 In most languages, the weak form of
substitutability is enforced
 Our designs should attempt to enforce the strong
form

(c) S. Thompson 12
Liskov Substitution
Ellipse
Principle
 Consider Circle & Ellipse
 A circle is a special case of ellipse
 So Inheritance could be used Circle
 Consider the following routines
 void Ellipse::SetFoci( point a, point b ) { focusA = a; focusB = b...}
 void Circle::SetFoci( point a, point b ) { focusA = a; focusB = a; }
 That works, but the behavior of a circle does not always conform
to an ellipse
Ellipse e = getEllipse();
e.SetFoci( 5, 10 );
assert( e. getFocusA() == 5 );
assert( e.getFocusB() == 10 );
 We have violated the contract of the base class

(c) S. Thompson 13
Liskov Substituion Priciple

 Eiffel uses preconditions and postconditions to


enforce contracts
 In terms of contracts, a derived class is
substitutable for its base class if:
 Its preconditions are no stronger than the base class
method.
 Its postconditions are no weaker than the base class
method.
 Or, in other words, derived methods should
expect no more and provide no less
 LSP violations are difficult to discover until it’s
too late
(c) S. Thompson 14
Dependency-Inversion
Principle
 Depend upon Abstractions. Do not depend
upon concretions.
 OCP is the goal – DIP is the primary
mechanism
 Procedural code tends to have high level code
depend on low level code, which in turns depends
on lower-level code.
 High-level code should depend on high-level
policies

(c) S. Thompson 15
Dependency-Inversion
Principle

(c) S. Thompson 16
Dependency-Inversion
Principle
 In an object-oriented world high-level policies
depend on abstractions
 The detailed implementations themselves
then depend on the abstractions
 Thus, we have inverted the dependency

(c) S. Thompson 17
Dependency-Inversion
Principle

(c) S. Thompson 18
Dependency-Inversion
Principle
 The reason for this is to not depend on
volatile code
 Difficult to follow all the time
 Dependency on non-volatile code (string.h for
example) is necessary
 Object creation code is dependent on concrete
classes
 See abstract factory....

(c) S. Thompson 19
The Interface Segregation
Principle
 Many client specific interfaces are better than
one general purpose interface
 Attempt to make classes and components
more portable
 Basis for COM and other component-based
technologies
 If you have a class used by several clients,
create several interfaces and use multiple
(interface) inheritance
(c) S. Thompson 20
The Interface Segregation
Principle
 Changes to service for A, effect B and C

Client A Service

Client B <<client A methods>>


<<client B methods>>
Client C <<client C methods>>

(c) S. Thompson 21
The ISP
 Instead we have specialized interfaces for
each client
<<interface>>
Client A Service A
<<clientA methods>>

<<interface>>
Client B Service B Service
<<clientB methods>>
<<client A methods>>
<<interface>> <<client B methods>>
Client C Service A <<client C methods>>
<<clientA methods>>
(c) S. Thompson 22
The Interface Segregation
Principle
 This doesn’t mean that every client always
gets it’s own interface
 Clients are categorized based on their type
 Can help to maintain backwards
compatibility by introducing new interfaces
for new code only
 Care should be taken to not overdo it!

(c) S. Thompson 23
The Single Responsibility
Principle
 There should never be more than one reason
for a class to change
 This principle is a means to reduce coupling in
applications
 If a class has more than one responsibility (i.e.
reason to change) then responsibilities
become coupled

http://www.objectmentor.com/resources/articles/srp.pdf (c) S. Thompson 24


The SRP

 Consider the following class


class Rectangle
{
double getArea() { ... }
void draw( Graphics g ) { ... }
}
 This class has two responsibilities
 Mathematical model of geometry
 Render a rectangle using a GUI
 Applications that want just the mathematical
model now require knowledge of the GUI
(c) S. Thompson 25
The SRP

 Instead – create two classes


 Changes to how the rectangle is rendered is
isolated to the Graphical Application

(c) S. Thompson 26

Potrebbero piacerti anche