When it comes to designing flexible, scalable, maintainable, and reusable code in software development, Object-Oriented Design is critical. There are numerous advantages to using OOD, but every developer should understand the SOLID concept for successful object-oriented programming design. Robert C. Martin, often known as Uncle Bob, established the SOLID principle, which is a programming coding standard. This principle is an abbreviation of the five principles listed below...
1. Single Responsibility Principle (SRP)
2. Open/Closed Principle
3. Liskov’s Substitution Principle (LSP)
4. Interface Segregation Principle (ISP)
5. Dependency Inversion Principle (DIP)
Tight coupling can be reduced using the SOLID concept. Tight coupling occurs when a group of classes is very reliant on one another, and it is something you should avoid in your code. Loose coupling is the polar opposite of tight coupling, and code with loosely coupled classes is considered good code. Loosely coupled classes let you write code that is more reusable, maintainable, flexible, and stable by reducing the number of changes you have to make. Let's take a look at each of these ideas one by one...
1. Single Responsibility Principle (SRP)This principle asserts that "a class should have only one cause to change," implying that each class should have only one task, job, or goal. Consider the case of software development. We can argue that everyone has a single job or responsibility because the task is separated into distinct individuals doing different things, such as front-end designers performing design, testers conducting testing, and backend developers taking care of backend development.
When programmers need to add new features or behaviour, they frequently do so by implementing everything into an existing class, which is entirely incorrect. It makes their code longer, more difficult, and time consuming when something needs to be changed later. In your application, use layers and divide God classes down into smaller classes or modules.
"Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification," according to this principle, which means you should be able to extend a class's behaviour without changing it.
If developer A has to issue an update for a library or framework, and developer B wants to make a change or add a feature, developer B is permitted to extend the existing class produced by developer A, but not to edit the class directly. This idea separates existing code from modified code, resulting in improved stability, maintainability, and the reduction of changes in your code.
Barbara Liskov proposed the principle in 1987, which states that "derived or child classes must be substitutable for their base or parent classes." This principle ensures that any child class of a parent class can be used in place of the parent class without causing any unexpected behaviour.
You can understand it in a way that a farmer’s son should inherit farming skills from his father and should be able to replace his father if needed. If the son wants to become a farmer then he can replace his father but if he wants to become a cricketer then definitely the son can’t replace his father even though they both belong to the same family hierarchy.
The rectangle with four sides is a famous example of this idea. The height and breadth of a rectangle can both be any value. A square is a rectangle that is the same width and height on all sides. As a result, we can say that the attributes of the rectangle class can be extended to the square class. To achieve this, you must replace the child (square) class with the parent (rectangle) class in order to conform to the definition of a square with four equal sides. However, a derived class has no effect on the behaviour of the parent class, so doing so would violate the Liskov Substitution Principle.
4. Interface Segregation Principle:This principle is the first principle that applies to Interfaces instead of classes in SOLID and it is similar to the single responsibility principle. It states that “do not force any client to implement an interface which is irrelevant to them“. Here your main goal is to focus on avoiding fat interface and give preference to many small client-specific interfaces. You should prefer many client interfaces rather than one general interface and each interface should have a specific responsibility.
Suppose if you enter a restaurant and you are pure vegetarian. The waiter in that restaurant gave you the menu card which includes vegetarian items, non-vegetarian items, drinks, and sweets. In this case, as a customer, you should have a menu card which includes only vegetarian items, not everything which you don’t eat in your food. Here the menu should be different for different types of customers. The common or general menu card for everyone can be divided into multiple cards instead of just one. Using this principle helps in reducing the side effects and frequency of required changes.
4. Dependency Inversion PrincipleBefore we begin, keep in mind that Dependency Inversion and Dependency Injection are two separate ideas. The majority of people are perplexed by this and believe that both are the same. Now there are two crucial aspects to remember about this principle.
High-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.
The above words basically explain that if a high module or class is more dependent on low-level modules or classes, your code will be tightly coupled, and if you alter one class, it will break another, which is dangerous at the production level. As a result, always aim to make classes as loosely connected as possible, which you may do through abstraction. The basic goal of this approach is to decouple dependencies such that if class A changes, class B doesn't have to be concerned or aware of the changes.
Consider the case of a TV remote battery in real life. Your remote requires a battery, but the brand does not matter. You can use whatever XYZ brand you want, and it will still work. As a result, we may argue that the TV remote is only tangentially linked to the brand name. Dependency Inversion improves the reusability of your code.
It reduces the dependencies so that a block of code can be changed without affecting the other code blocks.
The principles intended to make design easier, understandable.
By using the principles, the system is maintainable, testable, scalable, and reusable.
It avoids the bad design of the software.