object oriented design principles arnon rotem-gal-oz product line architect
TRANSCRIPT
Object Oriented Object Oriented Design PrinciplesDesign Principles
Arnon Rotem-Gal-OzArnon Rotem-Gal-OzProduct Line ArchitectProduct Line Architect
PrefacePreface
Nothing really new hereNothing really new hereJust a summary of other people’s work:Just a summary of other people’s work:
D.L. ParnasD.L. Parnas
M. FowlerM. Fowler
R.C. Martin, B. Meyer, B. LiskovR.C. Martin, B. Meyer, B. Liskov
W.J. Brown, R.C. Malveau, H.W. McCormick, W.J. Brown, R.C. Malveau, H.W. McCormick, T.J. MowbrayT.J. Mowbray
GoFGoF
N. MalikN. Malik
A. Holub A. Holub
And probably others I forgotAnd probably others I forgot
AgendaAgenda
7 Deadly Sins of Design7 Deadly Sins of Design
The RulesThe Rules
Basic StuffBasic Stuff
Evil StuffEvil Stuff
More StuffMore Stuff
7 Deadly Sins of Design7 Deadly Sins of Design
Rigidity – make it hard to change Rigidity – make it hard to change
Fragility – make it easy to breakFragility – make it easy to break
Immobility – make it hard to reuseImmobility – make it hard to reuse
Viscosity – make it hard to do the right Viscosity – make it hard to do the right thingthing
Needless Complexity – over designNeedless Complexity – over design
Needless Repetition – error proneNeedless Repetition – error prone
Not doing anyNot doing any
The RulesThe RulesApply Common SenseApply Common Sense
DDon’t get too dogmatic / religiouson’t get too dogmatic / religious
Every decision is a tradeoff Every decision is a tradeoff
All other principles are just that All other principles are just that GuidelinesGuidelines
““best practices”best practices”
Consider carefully if you should violate Consider carefully if you should violate them - but, know you can.them - but, know you can.
Basic StuffBasic Stuff
OCP open-closed principleOCP open-closed principle
SRP single responsibility principleSRP single responsibility principle
ISP interface segregation principleISP interface segregation principle
LSP Liskov substitution principleLSP Liskov substitution principle
DIP dependency inversion principleDIP dependency inversion principleDependency InjectionDependency Injection
Open Closed PrincipleOpen Closed Principle
Software entities ( Classes, Modules, Software entities ( Classes, Modules, Methods, etc. ) should be open for Methods, etc. ) should be open for extension, but closed for modification.extension, but closed for modification.
Also Known AsAlso Known AsProtected Variation Protected Variation
What Parnas meant when he coined What Parnas meant when he coined “Information hiding”“Information hiding”
Why OCPWhy 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 OCP Example
TemplateTemplateMethodMethod
OCP implications (examples)OCP implications (examples)
Use private modifier for class membersUse private modifier for class members
Refrain from adding Getters Refrain from adding Getters automaticallyautomatically
Use abstractions Use abstractions Extend by inheritance, delegationExtend by inheritance, delegation
Inversion of Control (IoC)Inversion of Control (IoC)
Single Responsibility Single Responsibility PrinciplePrinciple
A Class should have one reason to A Class should have one reason to changechange
A Responsibility is a reasons to changeA Responsibility is a reasons to change
Can be tricky to get granularity rightCan be tricky to get granularity right
Why SRPWhy SRP
Single Responsibility = increased Single Responsibility = increased cohesion cohesion
Not following results in needless Not following results in needless dependenciesdependencies
More reasons to change.More reasons to change.
Rigidity, Immobility Rigidity, Immobility
SRP Example (1/2)SRP Example (1/2)
The Rectangle has 2 responsibilitiesThe Rectangle has 2 responsibilities
Algorithm Client Application
Rectangle Draw()Area()
DirectX
Suddenly the Algorithm needs DirectXSuddenly the Algorithm needs DirectX
DependencyDependency
SRP Example (2/2)SRP Example (2/2)
RectangleArea()
ClientApplication
RectangleRenderer Draw()
DirectXAlgorithm
DependencyDependency
Interface Segregation Interface Segregation PrinciplePrinciple
Many client specific interfaces are Many client specific interfaces are better than one general purpose better than one general purpose interfaceinterface
Create an interface per client Create an interface per client typetype not not per client per client
Avoid needless coupling to clientsAvoid needless coupling to clients
Why ISPWhy ISP
Otherwise – increased coupling Otherwise – increased coupling between different clientsbetween different clients
Basically a variation on SRPBasically a variation on SRP
ISP exampleISP example
ClientApplication
RectangleImpl.
DirectXAlgorithm
DependencyDependency
IRectangleArea()
IRectangleRendererDraw()
RealizationRealization
Liskov Substitution PrincipleLiskov 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 EnglishOr in English
Any subclass should always be usable Any subclass should always be usable instead of its parent class.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 LSPWhy LSP
Failing to follow LSP result in a messFailing to follow LSP result in a messOCP violations (if/then to identify types)OCP violations (if/then to identify types)
Superclass unit test will failSuperclass unit test will fail
Strange behavior Strange behavior
Trivial ExampleTrivial Example
Why is that an LSP violation?Why is that an LSP violation?cd Diagram Examples
Rectangle
+ SetHight() : void+ SetWidth() : void
Square
+ SetHight() : void+ SetWidth() : void
Real-Life ExampleReal-Life Example
cd Diagram Examples
ContextBoundObject
MarshalByRefObject
cd Diagram Examples
«interface»
IContributeObjectSink{abstract}
+ GetObjectSink(MarshalByRefObject, IMasshageSink) : IMessageSink {abstract}
.NET creates a transparent proxy and.NET creates a transparent proxy andintercepts all calls to ContextBoundObjectsintercepts all calls to ContextBoundObjects Implementing IContextObjectSink On a Implementing IContextObjectSink On a class derived from ContrextAttribute class derived from ContrextAttribute lets you add a sink in the chainlets you add a sink in the chain
Real-Life ExampleReal-Life Examplecd Diagram Examples
ServicedComponent
ContextBoundObject
MarshalByRefObject ServicedComponentsServicedComponents violates LSP:violates LSP:
You cannot add your own sinksYou cannot add your own sinks(it only uses its own)(it only uses its own)
Dependency Inversion Dependency Inversion PrinciplePrinciple
Higher level modules should not Higher level modules should not depend on lower level modulesdepend on lower level modules
Both should depend on abstractions Both should depend on abstractions Interfaces or Abstract classesInterfaces or Abstract classes
Abstractions should not depend on Abstractions should not depend on detailsdetails
(Not to be confused with Dependency (Not to be confused with Dependency Injection and Inversion of Control)Injection and Inversion of Control)
Why DIPWhy DIP
Increase loose couplingIncrease loose couplingAbstract interfaces don't changeAbstract interfaces don't changeConcrete classes implement interfacesConcrete classes implement interfacesConcrete classes easy to throw away and replaceConcrete classes easy to throw away and replace
Increase mobilityIncrease mobilityIncrease isolation Increase isolation
decrease rigiditydecrease rigidityIncrease testabilityIncrease testabilityIncrease maintainablityIncrease maintainablity
Closely related to LSP Closely related to LSP
Reminder - Procedural DesignReminder - Procedural Design
cd Diagram Examples
:Module:Module:Module
:Program
:Function :Function :Function :Function
DIP DIP cd Diagram Examples
:Program
:Class1 :Class2 :Class3 :Class4
«interface»
:Interface1
«interface»
:Interface2
«interface»
:Interface3
«realize» «realize» «realize»«realize»
DIP implicationsDIP implications
LayersLayers
Interface based programming Interface based programming
Separated Interface Separated Interface put interface in separate package than put interface in separate package than implementationimplementation
Dependency InjectionDependency Injection
Old WayOld Way
public class MyApppublic class MyApp{{
public MyApp()public MyApp(){{
authenticator = new Authenticator();authenticator = new Authenticator();database = new Database();database = new Database();logger = new Logger();logger = new Logger();errorHandler = new ErrorHandler();errorHandler = new ErrorHandler();
}}
// More code here...// More code here...
}}
Dependency InjectionDependency Injection
DIP says we should depend on an DIP says we should depend on an interface interface
how do we get the concrete instancehow do we get the concrete instance
New Way?New Way?
public class MyApppublic class MyApp{{
public MyApp()public MyApp(){{
authenticator = new authenticator = new IIAuthenticator();Authenticator();database = new database = new IIDatabase();Database();logger = new logger = new IILogger();Logger();errorHandler = new errorHandler = new IIErrorHandler();ErrorHandler();
}}
// More code here...// More code here...
}}
OOPSOOPS
Dependency Injection Dependency Injection
Option 1 – FactoryOption 1 – FactoryUser depends on factoryUser depends on factory
Factory depends on destinationFactory depends on destination
Option 2 – Locator/Registry/DirectoryOption 2 – Locator/Registry/DirectoryThe component still controls the wiringThe component still controls the wiring
Instantiation Sequence Instantiation Sequence
Dependency on the LocatorDependency on the Locator
Option 3 – Dependency InjectionOption 3 – Dependency InjectionAn assembler controls the wiringAn assembler controls the wiring
DI OptionsDI Options
Setter InjectionSetter InjectionThe component is passiveThe component is passive
Someone injects the Someone injects the
dependencydependency
DI OptionsDI Options
Setter InjectionSetter Injection
Constructor InjectionConstructor Injection““Always” initializedAlways” initialized
Better dependency visibilityBetter dependency visibility
Other DI OptionsOther DI Options
Interface Injection Interface Injection Variation on setter injectionVariation on setter injection
Getter InjectionGetter InjectionNeeds AOP (not clean)Needs AOP (not clean)
Evil StuffEvil StuffSwitch statementsSwitch statements
If (type()) If (type())
Singletons / Global variablesSingletons / Global variables
GettersGetters
Helper ClassesHelper Classes
More StuffMore Stuff
Package principlesPackage principlesNot the core of this presentationNot the core of this presentation
SSmellsmells
Anti-PatternsAnti-Patterns
Package PrinciplesPackage Principles
Reuse-Release Equivalency PrincipleReuse-Release Equivalency Principle
Common Closure PrincipleCommon Closure Principle
Common Reuse PrincipleCommon Reuse Principle
Acyclic Dependencies PrincipleAcyclic Dependencies Principle
Stable Dependencies PrincipleStable Dependencies Principle
Stable Abstractions PrincipleStable Abstractions Principle
CodeSmellsCodeSmells
Something that's quick to spot Something that's quick to spot
Indication for a possible problemIndication for a possible problemNot always the problem it selfNot always the problem it self
May not be a problem at allMay not be a problem at all
CodeSmell example – Long MethodCodeSmell example – Long Method
DDesignSmellesignSmell (1) (1)
Many CodeSmells can also apply to Many CodeSmells can also apply to designdesign
Long Parameter ListLong Parameter List
Large Class (Swiss Army knife / Blob)Large Class (Swiss Army knife / Blob)
Type Embedded in Name Type Embedded in Name
Uncommunicative Name Uncommunicative Name
Data Class Data Class
Refused Bequest (LSP violations)Refused Bequest (LSP violations)
DesignSmell (2)DesignSmell (2)
Inappropriate Intimacy Inappropriate Intimacy
Lazy Class Lazy Class
Feature Envy (Managers)Feature Envy (Managers)
Shotgun Surgery Shotgun Surgery
Parallel Inheritance Hierarchies Parallel Inheritance Hierarchies
Message Chains Message Chains
Component Without InterfaceComponent Without Interface
SingletonsSingletons
Design Related Anti-PatternsDesign Related Anti-Patterns
The BlobThe Blob
Functional DecompositionFunctional Decomposition
PoltergeistPoltergeist
Golden HammerGolden Hammer
Swiss Army Knife Swiss Army Knife
Kevorkian Component (Dead End)Kevorkian Component (Dead End)
(Other Anti-Patterns deal with(Other Anti-Patterns deal with
Architecture, Management, Code)Architecture, Management, Code)