“The Single Responsibility Principle states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.”
“There should never be more than one reason for a class to change.” - Robert C. “Uncle Bob” Martin
Cohesion
Relation of responsibilities
Focused on one task
Coupling
Dependency on other modules
Relationship between modules
Ideal - low coupling / strong cohesion
Responsibilities
“A reason to change”
Mapped to project requirements
More requirements – more possible changes
More responsibilities – more changes in code
Multiple responsibilities in one class – coupling
More coupling – more errors on change
Classicviolations
Objects that can print/draw themselves
Objects that can save/restore themselves
Classic solution
Separate printer
Separate saver (or memento)
Solution
Multiple small interfaces (ISP)
Many small classes
Distinct responsibilities
Result
Flexibledesign
Lower coupling
Higher cohesion
OCP
"TheOpen / Closed Principle states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."
Open to Extension
New behavior can be added in the future
Closed to Modification
Changes to source or binary code are not required
Change behavior without changing code?!
Rely on abstractions, not implementations
Do not limit the variety of implementations
In .NET
Interfaces
Abstract Classes
In procedural code
Use parameters
Classicviolations
Each change requires re-testing (possible bugs)
Cascading changes through modules
Logic depends on conditional statements
Classic solution
New classes (nothing depends on them yet)
New classes (no legacy coupling)
Three approaches to achieve OCP
Parameters
Pass delegates / callbacks
Inheritance / Template Method pattern
Child types override behavior of a base class
Composition / Strategy pattern
Client code depends on abstraction
“Plug in” model
When to apply OCP?
Experience tell you
“Fool me once, shame on you”
Don’t apply OCP at first
If module changes once, accept it
If it changes a second time, refactor for OCP
OCP add complexity to design(TANSTAAFL)
No design can be closed against all changes
LSP
"TheLiskovSubstitution Principle states that Subtypes must be substitutable for their base types."
Substitutability – child classes must not
Remove base class behavior
Violate base class invariants
Normal OOP inheritance
IS-A relationship
LiskovSubstitutioninheritance
IS-SUBSTITUTABLE-FOR
The problem
Polymorphism break
Client code expectations
“Fixing” by adding if-then – nightmare (OCP)
Classicviolations
Type checking for different methods
Not implemented overridden methods
Virtual methods in constructor
Solutions
“Tell, Don’t Ask”
Don’t ask for types
Tell the object what to do
Refactoring to base class
Common functionality
Introduce third class
ISP
"TheInterface Segregation Principle states that Clients should not be forced to depend on methods they do not use."
Prefer small , cohesive interfaces
Divide “fat” interfaces into smaller ones
Interface is:
The interface type
All public members of a class
Having “fat” interfaces leads to:
Classes having methods they do not need
Increasing coupling
Reduced flexibility
Reduced maintainability
Classic violations
Unimplemented methods (also in LSP)
Use of only small portion of a class
When to fix?
Once there is pain! Do not fix, if is not broken!
If the “fat” interface is yours, separate it to smaller ones
If the “fat” interface is not yours, use “Adapter” pattern
Solutions
Small interfaces
Cohesive interfaces
Focused interfaces
Let the client define interfaces
Package interfaces with their implementation
DIP
"High-levelmodules should not depend on low-level modules. Both should depend on abstractions."
"Abstractionsshould not depend on details. Details should depend on abstractions."
Dependency is:
Framework
ThirdParty Libraries
Database
FileSystem
Email
WebServices
SystemResources (Clock)
Configuration
Thenew Keyword
Staticmethods
Thread.Sleep
Random
Traditional Programming
High level modules use lower lever modules
UI depends on Business Layer
Business layer depends on
Infrastructure
Database
Utilities
Static methods (Façade for example)
Classes instantiated everywhere
How it should be
Classes should declare what they need
Constructors should require dependencies
Hidden dependencies should be shown
Dependencies should be abstractions
How to do it
Dependency Injection
The Hollywood principle"Don’t call us, we’ll call you!"