SOLID – Object oriented programming principles.
May be its easy to forget these principles but for creating a reusable code or maintainable code, people will always have to come back and check these principles for robust design. Today, We will explore these principles, not in terms of definition or meaning but why they are required or how they can help in designing our system.
S –Single responsibility principle
Wikipedia defines it as “every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class”.
The idea behind this principle is that, if you have a class and there are some situation like
- there are dependent or inherited classes.
- there is some consumer flow attached to it.
So if we go ahead and introduce any change to our main class then this change should only be limited to this class . None of the dependent classes or consumers should have to be modified to adjust to this change.
How and why?
By following this principle, we can limit the number of places we have to change the code for a single change anywhere. It can facilitate clean code and division.
Other than the advantages mentioned above, following this principle leads to
- Simple code.
- understandable design.
O –Open/closed principle
Wikipedia definition says “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”
When we write a code, we ,somewhat has to predict the possible changes coming , as it is a well-known fact that the code that we are writing is susceptible to change when we are writing it. However if the developer is inexperienced and is not able to predict the possible changes, so to deal with it ,go ahead and write the simple code.
How and why?
Although, the moment the changes are requested then he should be ready to introduce this principle and works on the extension of the code and make it more robust.
As per the principle, software design should be open for extensions and closed for modifications . This is a tough prediction and involvement of developer / designer is required to identify what areas of his code are susceptible to change.
L – Liskov Substitution Principle
Wikipedia definition – “if S is a subtype of T, then objects of type T may be replaced with objects of type S”
This line always confused the readers as they talk about interchangeable principle between base types and sub-types. if sub-types can replace base-types then why do we required base types at all?
The primary objective of this design is that the code while calling should not know the difference between the base type and a sub type. If your code is using base-type instance as a parameter then if we replace the parameter with sub-type, then also,our code should work.
One area where this principle can NOT be applied is when the subtype implement only one (or few) operations of the base type. This means that subtypes are not exactly replaceable substitutes of base-type.
How and why?
Imagine you have a code to book a vehicle for transportation, this ‘vehicle’ instance is a parameter in this code, trust this ‘vehicle’ instance as a base-type and if you replace it with a sub-type like ‘Bus’ then also your code for transportation should work.
Any operation that can be performed on a subtype but cannot be done on another subtype with the same parent, then this principle is compromised.
I – Interface Segregation Principle
For this principle,idea is to use customer centric interface. How? class and interface are interchangeable terms.
When client asks for only a few operations, then we should provide only those operation with the help of interface . Don’t try to build a single interface, but try to declare many individual interfaces.
Interface segregation violations result in classes that depend on interfaces they do not need, increasing coupling and reducing flexibility and maintainability.
How and Why?
If you have built a fat interface, and Client references this interface but only uses a part of it then your principle is not valid. This is where coder has to provide multiple interfaces so that client will refer to only those interfaces which are required and leave other interfaces.
If you have a problem using a fat interface, then go for adapter pattern and generate a single interface which will work as an adapter to this fat interface.
D – Dependency Injection / Inversion of control
We have .Net MVC fully utilizing this principle.
Wikipedia: The principle states:
- A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
- B. Abstractions should not depend upon details. Details should depend upon abstractions.
Here, the definition is much more clear but still difficult to implement. Idea is that, we should not declare tight coupling between details and abstractions. Like, If i have a phone and i just want to send somebody a message through this, then I’ll just be dependent on my phone interface and not worried about the network as how it will reach the reception point.
How and why?
First of all,chuck out all the dependencies that are in your implementation. Once you are able to chuck out, start changing the code and provide an option to introduce these dependencies from outside.
you can use patterns like Unity and all to learn the principle.