OBJECT ORIENTED DESIGN
In object-oriented computer programming, SOLID is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable. These principles, when combined together, make it easy for a programmer to develop software that are easy to maintain and extend. They also make it easy for developers to avoid code smells, easily refactor code, and are also a part of the agile or adaptive software development.
S.O.L.I.D stands for:
S - Single-responsiblity principle
O - Open-closed principle
L - Liskov substitution principle
I - Interface segregation principle
D - Dependency Inversion Principle
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.
Open–closed principle (OCP) Software entities ... should be open for extension, but closed for modification. In other words, Objects or entities should be open for extension, but closed for modification. This means that a class should be easily extendable without modifying the class itself.
Liskov substitution principle (LSP) Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
Note: You must be aware that you can use an object of a derived class anywhere where base class is expected. However, when such a substitution occurs the functionality and correctness of the code shouldn't change.
Interface segregation principle (ISP) Many client-specific interfaces are better than one general-purpose interface. 1. No client should be forced to depend on methods it does not use. Many client-specific interfaces are better than one general-purpose interface. 2. We can define it in another way. 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 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.
Dependency inversion principle (DIP) One should depend upon abstractions, not concretions. High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. In other words 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 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/class 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.