Apprenticeship blog 1: SOLID principles
S - Single Responsibility Principle
what it means: “There should never be more than one reason for a class to change.”
O - Open-Closed Principle(OCP)
what it means: Open for expansion but closed for for modulation.
L - Liskov Substitution Principle(LSP)
what it means: Functions that use pointers/references to base classes must be able to use objects of derived classes w/o knowing it.
If there’s a function that doesn’t conform to LSP, then that function uses a pointer/reference to a base class, but must know about all the derivatives of that base class.
If it doesn’t conform to LSP, it must be modified whenever a new derivative of the base class is created.
Example of LSP violation: using rectangle class to derive square class.
But that means that height = width for all cases, which you can’t do when you treat a square as a rectangle!
LSP is an important feature of all programs that conform to Open-Closed principle.
I - Interface Segregation Principle(ISP)
ISP deals with the disadvantages of “fat” interfaces.
"fat" interfaces: classes whose interfaces are not cohesive.
non-cohesive: the interfaces of a class can be broken up into groups of member functions. Each group serves a different set of clients. Thus some clients use one group of member functions, and other clients use the other groups. In other words, cohesion is the degree to which elements of a module belong together.
Example: a base door class has a ‘timed door’ subclass that uses a ‘timed client’ class. Therefore, we decide to make ‘door’ class dependent on ‘timed client’, and any changes to the ‘timed client’ will affect ALL door subclasses, even if they don’t use the ‘timed client’.
what it means: ISP suggests that clients should not know about non-cohesive interfaces as a single class, but should know about abstract base classes that have cohesive interfaces.
In other words, clients should not be forced to depend upon interfaces that they do not use.
Class Interfaces v. Object Interfaces:
clients of an object do not need to access it through the interface of the object. Rather, they can access it through delegation, or through a base class of the object.
Example of separation through delegation: TimedDoor is subclass of abstract Door base class. TimedDoor creates a DoorTimerAdapter subclass of abstract TimerClient class and registers it with its timer. When TimeOut message occurs, DoorTimerAdapter delegates the message back to the TimedDoor.
D - Dependency Inversion Principle
It is hard to change because every change affects too many other parts of the system.(Rigidity)
When you make a change, unexpected parts of the system may break.(Fragility)
It is hard to reuse in another application because it cannot be disentangled from the current application.(Immobility)
Example of bad design: A copy program that depends upon a keyboard for input and a printer for output. If you wanted to, say, output to memory, you would have to change the code to accept the new output.
Example of good design: A copy program that depends upon an abstract class for input and an abstract class for output.
what it means: The structure that results from rigorous use of OCP and LSP can be generalized into a principle all by itself.
High level modules should not depend upon low level modules. Both should depend upon abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.