If a class has more than one responsibility, it becomes
coupled. A change to one
responsibility results to modification of the other responsibility
O: Open-Closed Principle
Software entities(Classes, modules, functions) should be open for extension,
not modification.
You should be able to add more functionality to the class but
do not edit current functions in a way that breaks existing code that uses it.
Animal now has a virtual method makeSound. We have each animal
extend the Animal class and implement the virtual makeSound method.
Every animal adds its own implementation on how it makes a
sound in the makeSound. The AnimalSound iterates through the array of animal and just calls its makeSound
method.
Now, if we add a new animal, AnimalSound doesn’t need to
change. All we need to do is add the new animal to the animal array.
AnimalSound now conforms to the OCP principle. You see,
extension without modification.
L: Liskov Substitution Principle
A sub-class must be substitutable for its super-class
Use inheritance in a way that will not break the application
logic at any point
ChildClass shall not replicate a functionality of ParentClass
in a way that changes the behavior of the ParentClass...so you can easily use the object of ChildClass instead
of the obect of ParentClass without breaking the application logic
The aim of this principle is to ascertain that a sub-class can
assume the place of its super-class without errors. If the code finds itself checking the type of class then,
it must have violated this principle.
I: Interface Segregation Principle
Make fine grained interfaces that are client specific.
Clients should not be forced to depend upon interfaces that they do not use.
Since a class can implement multiple interfaces, structure your code in a way
that a class will never be forced to implement a function that is not important to its purpose.
This interface draws squares, circles, rectangles. class
Circle, Square or Rectangle implementing the IShape interface must define the methods drawCircle(),
drawSquare(),drawRectangle().
...(and often times the class implementing the interface (such as a circle)...has no use for drawSquare())
Also, ISP states that interfaces should perform only one job
(just like the SRP principle) any extra grouping of behavior should be abstracted away to another interface.
D: Dependency Inversion Principle
Dependency should be on abstractions not concretions
A) High-level modules should not depend upon low-level modules.
Both should depend upon abstractions.
B) Abstractions should not depend on details. Details should
depend upon abstractions.
If a PurchaseClass depends on a UserClass...then the UserClass object
instantiation should come from outside the PurchaseClass.
(below violates)
class XMLHttpService extends XMLHttpRequestService {}class Http {
constructor(private xmlhttpService: XMLHttpService) { }
get(url: string , options: any) {
this.xmlhttpService.request(url,'GET');
} post() {
this.xmlhttpService.request(url,'POST');
}
}
Here, Http is the high-level component whereas HttpService is the low-level component. This design violates
DIP A: High-level modules should not depend on low-level level modules. It should depend upon its abstraction.
The Http class should care less the type of Http service you
are using. We make a Connection interface:
interface Connection {
request(url: string, opts:any);
}
abstractions = interfaces
Now, we can see that both high-level modules and low-level
modules depend on abstractions. Http class(high level module) depends on the Connection interface(abstraction)
and the Http service types(low level modules) in turn, depends on the Connection interface(abstraction).
Also, this DIP will force us not to violate the Liskov Substitution Principle: The Connection types
Node-XML-MockHttpService are substitutable for their parent type Connection.