SOLID Principle in ProgrammingAmr Saafan
When it comes to writing 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 also understand the SOLID principle for good object-oriented design in programming. The SOLID principle, introduced by Robert C. Martin, also known as Uncle Bob, is a programming coding standard. This principle is an abbreviation for the five principles listed below…
- Single Responsibility Principle (SRP)
- Open/Closed Principle
- Liskov’s Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
The SOLID principle aids in the reduction of tight coupling. Tight coupling describes a group of classes that are highly dependent on one another and should be avoided in your code. The inverse of tight coupling is loose coupling, and your code is considered good if it has loosely-coupled classes. Loosely coupled classes help to reduce changes in your code, making it more reusable, maintainable, flexible, and stable. Let us now go over these principles one by one…
1.The Single Responsibility Principle
States that “a class should have only one reason to change,” which means that each class should have a single responsibility, job, or purpose. Consider the development of software. The task is divided into different members doing different things, such as front-end designers doing design, testers doing testing, and backend developers handling backend development, so everyone has a single job or responsibility.
When programmers have to add features or new behavior, they frequently implement everything into the existing class, which is completely incorrect. It lengthens, complicates, and wastes time when something needs to be changed later. In your application, use layers to divide God classes into smaller classes or modules.
2. Open/Closed Principle
According to this principle, “software entities (classes, modules, functions, etc.) should be open for extension but closed for modification,” which means that you should be able to extend a class’s behavior without modifying it.
If developer A needs to release an update for a library or framework and developer B wants to make a change or add a feature to it, developer B is permitted to extend the existing class created by developer A but is not permitted to modify the class directly. Using this principle separates the existing code from the modified code, which improves stability and maintainability while minimizing changes in your code.
3. Liskov’s Substitution Principle
Barbara Liskov introduced the principle in 1987, and it states that “derived or child classes must be substitutable for their base or parent classes.” This principle ensures that any class that is a child of a parent class can be used in place of its parent without exhibiting unexpected behavior.
You can think of it this way: a farmer’s son should inherit his father’s farming skills and be able to replace his father if necessary. If the son wants to be a farmer, he can replace his father; however, if he wants to be a cricketer, he cannot replace his father, even though they both belong to the same family hierarchy.
A rectangle with four sides is a classic example of this principle. The height and width of a rectangle can be any value. A square is a rectangle that has the same width and height. As a result, we can say that the properties of the rectangle class can be extended to the square class. To fit the definition of a square with four equal sides, you must swap the child (square) class with the parent (rectangle) class, but a derived class does not affect the behavior of the parent class, so doing so violates the Liskov Substitution Principle.
4. Interface Segregation Principle
This is the first principle in SOLID that applies to interfaces rather than classes, and it is similar to the single responsibility principle. It states that “no client should be forced to implement an interface that is irrelevant to them.” The main goal here is to avoid fat interfaces and priorities many small client-specific interfaces. You should prefer multiple client interfaces to one general interface, and each interface should be responsible for something specific.
Assume you walk into a restaurant and are a strict vegetarian. The waiter at that restaurant handed you a menu card with vegetarian and non-vegetarian options, drinks, and desserts. As a customer, you should have a menu card that only includes vegetarian items, not everything that you don’t eat in your food. The menu should be different for each type of customer. Instead of just one card, the common or general menu card for everyone can be divided into multiple cards. Using this principle reduces the number of required changes and their side effects.
5. Dependency Inversion Principle
Before we begin, keep in mind that Dependency Inversion and Dependency Injection are two distinct concepts. Most people are perplexed by it and believe they are interchangeable. There are two key points 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 preceding lines simply state that if a high-level module or class is more dependent on low-level modules or classes, your code will have tight coupling, and changing one class can break another, which is risky at the production level. So, always try to make classes as loosely coupled as possible, which you can do through abstraction. The main goal of this principle is to decouple dependencies so that if class A changes, class B does not need to care or be aware of the changes.
Consider the real-world example of a TV remote battery. Your remote requires a battery, but the brand does not matter. You can use any XYZ brand you want and it will still work. As a result, we can say that the TV remote is only loosely associated with the brand name. Dependency Inversion improves the reusability of your code.