You are on page 1of 43

Object Oriented

Design Principles

Arnon Rotem-Gal-Oz
Product Line Architect
Preface
Nothing really new here
Just a summary of other people’s work:
D.L. Parnas
M. Fowler
R.C. Martin, B. Meyer, B. Liskov
W.J. Brown, R.C. Malveau, H.W. McCormick,
T.J. Mowbray
GoF
N. Malik
A. Holub
And probably others I forgot
Agenda
7 Deadly Sins of Design
The Rules
Basic Stuff
Evil Stuff
More Stuff
7 Deadly Sins of Design
Rigidity – make it hard to change
Fragility – make it easy to break
Immobility – make it hard to reuse
Viscosity – make it hard to do the right
thing
Needless Complexity – over design
Needless Repetition – error prone

Not doing any


The Rules
Apply Common Sense
Don’t get too dogmatic / religious
Every decision is a tradeoff

All other principles are just that


Guidelines
“best practices”
Consider carefully if you should violate
them - but, know you can.
Basic Stuff
OCP open-closed principle
SRP single responsibility principle
ISP interface segregation principle
LSP Liskov substitution principle
DIP dependency inversion principle
Dependency Injection
Open Closed Principle
Software entities ( Classes, Modules,
Methods, etc. ) should be open for
extension, but closed for modification.

Also Known As
Protected Variation
What Parnas meant when he coined
“Information hiding”
Why OCP
If not followed a single change to a
program results in a cascade of changes
to dependent modules.
The program becomes fragile, rigid,
unpredictable and un-reusable.
OCP Example

Template
Method
OCP implications (examples)
Use private modifier for class members

Refrain from adding Getters


automatically

Use abstractions
Extend by inheritance, delegation

Inversion of Control (IoC)


Single Responsibility
Principle
A Class should have one reason to
change
A Responsibility is a reasons to change

Can be tricky to get granularity right


Why SRP
Single Responsibility = increased
cohesion
Not following results in needless
dependencies
More reasons to change.
Rigidity, Immobility
SRP Example (1/2)
The Rectangle has 2 responsibilities

Algorithm Rectangle Client


Draw() Application
Area()

DirectX

Dependency

Suddenly the Algorithm needs DirectX


SRP Example (2/2)

Rectangle Rectangle Client


Area() Renderer Application
Draw()

Algorithm
DirectX
Dependency
Interface Segregation
Principle
Many client specific interfaces are
better than one general purpose
interface

Create an interface per client type not


per client
Avoid needless coupling to clients
Why ISP
Otherwise – increased coupling
between different clients

Basically a variation on SRP


ISP example

IRectangle IRectangle
Area() Renderer
Draw()

Rectangle Client
Impl. Application

Algorithm
DirectX
Realization

Dependency
Liskov Substitution Principle
“What is wanted here is something like the
following substitution property: 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 for o2
then S is a subtype of T.” (Barbara Liskov,
1988)
Or in English
Any subclass should always be usable
instead of its parent class.

Corollary - All derived classes must


honour the contracts of their base
classes
IS A = same public behavior
Pre-conditions can only get weaker
Post-conditions can only get stronger
Why LSP
Failing to follow LSP result in a mess
OCP violations (if/then to identify types)
Superclass unit test will fail
Strange behavior
Trivial Example

cd Diagram Examples
Why is that an LSP violation?
Rectangle

+ SetHight() : void
+ SetWidth() : void

Square

+ SetHight() : void
+ SetWidth() : void
Real-Life Example
cd Diagram Examples
cd Diagram Examples
«interface»
IContributeObjectSink
MarshalByRefObject {abstract}
+ GetObjectSink (MarshalByRefObject, IMasshageSink ) : IMessageSink {abstract}

.NET creates a transparent proxy and


intercepts all calls to ContextBoundObjects
ContextBoundObject
Implementing IContextObjectSink On a
class derived from ContrextAttribute
lets you add a sink in the chain
Real-Life Example
cd Diagram Examples

MarshalByRefObject
ServicedComponents
violates LSP:

ContextBoundObject
You cannot add your own sinks
(it only uses its own)

ServicedComponent
Dependency Inversion
Principle
Higher level modules should not
depend on lower level modules
Both should depend on abstractions
Interfaces or Abstract classes
Abstractions should not depend on
details

(Not to be confused with Dependency


Injection and Inversion of Control)
Why DIP
Increase loose coupling
Abstract interfaces don't change
Concrete classes implement interfaces
Concrete classes easy to throw away and replace
Increase mobility
Increase isolation
decrease rigidity
Increase testability
Increase maintainablity

Closely related to LSP


Reminder - Procedural Design

cd Diagram Examples

:Program

:Module :Module :Module

:Function :Function :Function :Function


DIP
cd Diagram Examples

:Program

«interface» «interface» «interface»


:Interface1 :Interface2 :Interface3

«realize» «realize» «realize» «realize»

:Class1 :Class2 :Class3 :Class4


DIP implications
Layers

Interface based programming

Separated Interface
put interface in separate package than
implementation

Dependency Injection
Old Way
public class MyApp
{
public MyApp()
{
authenticator = new Authenticator();
database = new Database();
logger = new Logger();
errorHandler = new ErrorHandler();
}

// More code here...


}
Dependency Injection
DIP says we should depend on an
interface
how do we get the concrete instance
New Way?
public class MyApp
{
public MyApp()
{

P S
authenticator = new IAuthenticator();
O
O
database = new IDatabase();
logger = new ILogger();
errorHandler = new IErrorHandler();
}

// More code here...


}
Dependency Injection
Option 1 – Factory
User depends on factory
Factory depends on destination
Option 2 – Locator/Registry/Directory
The component still controls the wiring
Instantiation Sequence
Dependency on the Locator
Option 3 – Dependency Injection
An assembler controls the wiring
DI Options
Setter Injection
The component is passive
Someone injects the
dependency
DI Options
Setter Injection
Constructor Injection
“Always” initialized
Better dependency visibility
Other DI Options
Interface Injection
Variation on setter injection
Getter Injection
Needs AOP (not clean)
Evil Stuff
Switch statements

If (type())

Singletons / Global variables

Getters

Helper Classes
More Stuff
Package principles
Not the core of this presentation
Smells
Anti-Patterns
Package Principles
Reuse-Release Equivalency Principle
Common Closure Principle
Common Reuse Principle
Acyclic Dependencies Principle
Stable Dependencies Principle
Stable Abstractions Principle
CodeSmells
Something that's quick to spot
Indication for a possible problem
Not always the problem it self
May not be a problem at all

CodeSmell example – Long Method


DesignSmell (1)
Many CodeSmells can also apply to
design
Long Parameter List
Large Class (Swiss Army knife / Blob)
Type Embedded in Name
Uncommunicative Name
Data Class
Refused Bequest (LSP violations)
DesignSmell (2)
Inappropriate Intimacy
Lazy Class
Feature Envy (Managers)
Shotgun Surgery
Parallel Inheritance Hierarchies
Message Chains
Component Without Interface
Singletons
Design Related Anti-Patterns
The Blob
Functional Decomposition
Poltergeist
Golden Hammer
Swiss Army Knife
Kevorkian Component (Dead End)

(Other Anti-Patterns deal with


Architecture, Management, Code)
Thank you…
Arnon Rotem-Gal-Oz
arnon@rgoarchitects.com

You might also like