S.O.L.I.D. Priniciple
a design principle intended to make software designs more understandable, flexible and maintainable
S: Single Responsibility Principle (SRP)
A class should only have a single responsibility, that is, only changes to one part of the software’s specification should be able to affect the specification of the class.
The SRP states that "Every software module should have only one reason to change".
This means that every class, or similar structure, in your code should have only one job to do. Everything in that class should be related to a single purpose. Our class should not be like a Swiss knife wherein if one of them needs to be changed then the entire tool needs to be altered. It does not mean that your classes should only contain one method or property. There may be many members as long as they relate to single responsibility.
Example Scenario : An Account class is responsible for managing Current and Saving Account but a CurrentAccount and a SavingAccount classes would be responsible for managing current and saving accounts respectively. Hence both are responsible for single purpose only.
O: Open Closed Principle (OCP)
Software entities should be open for extension, but closed for modification.
The OCP states that "A software module/class is open for extension and closed for modification".
Here "Open for extension" means, we need to design our module/class in such a way that the new functionality can be added only when new requirements are generated. "Closed for modification" means we have already developed a class and it has gone through unit testing. We should then not alter it until we find bugs. As it says, a class should be open for extensions, we can use inheritance to do this
Example Scenario : A PaymentGateway base class contains all basic payment related properties and methods. This class can be extended by different PaymentGateway classes for different payment gateway vendors to achieve theirs functionalities. Hence it is open for extension but closed for modification.
L: Liskov Substitution Principle (LSP)
Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
The LSP states that "You should be able to use any derived class instead of a parent class and have it behave in the same manner without modification".
It ensures that a derived class does not affect the behavior of the parent class, in other words, that a derived class must be substitutable for its base class.
I: Interface Segregation Principle (ISP)
Many client-specific interfaces are better than one general-purpose interface.
The ISP states that "clients should not be forced to implement interfaces they don't use. Instead of one fat interface, many small interfaces are preferred based on groups of methods, each one serving one submodule.".
An interface should be more closely related to the code that uses it than code that implements it. So the methods on the interface are defined by which methods the client code needs rather than which methods the class implements. So clients should not be forced to depend upon interfaces that they don't use.
Like classes, each interface should have a specific purpose/responsibility (refer to SRP). You shouldn't be forced to implement an interface when your object doesn't share that purpose. The larger the interface, the more likely it includes methods that not all implementers can do. That's the essence of the Interface Segregation Principle. Let's start with an example that breaks the ISP. Suppose we need to build a system for an IT firm that contains roles like TeamLead and Programmer where TeamLead divides a huge task into smaller tasks and assigns them to his/her programmers or can directly work on them.
D: Dependency Inversion Principle (DIP)
One should depend upon abstractions, rather than concrete implementations.
The DIP states that "high-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions".
High-level modules/classes implement business rules or logic in a system (application). Low-level modules/classes deal with more detailed operations; in other words they may deal with writing information to databases or passing messages to the operating system or services.
A high-level module/class that has a dependency on low-level modules/classes or some other class and knows a lot about the other classes it interacts with is said to be tightly coupled. When a class knows explicitly about the design and implementation of another class, it raises the risk that changes to one class will break the other class. So we must keep these high-level and low-level modules/classes loosely coupled as much as we can. To do that, we need to make both of them dependent on abstractions instead of knowing each other.
Last updated
Was this helpful?