SOLID Principles: A set of guidelines for writing clean and maintainable code (CONTD)
- March 4, 2023
- Posted by: webadmin
- Category: Technology
Next up on the SOLID principle acronym is the L which denotes: Liskov Substitution Principle(LSP).
Liskov Substitution Principle (LSP):
The LSP states that objects of a superclass should be replaceable with objects of its subclasses without breaking the program’s correctness. This principle ensures that any function that works with a superclass will also work with its subclasses.
For example, let’s consider a classic example of LSP violation – a square and a rectangle. In geometry, a square is a special case of a rectangle where all sides are equal. However, if we implement the Square class as a subclass of Rectangle, we will run into trouble. If we change the width of the Square, we also have to change the height to keep it in shape as a square. This violates the LSP because we cannot use a Square object in place of a Rectangle object.
A better solution would be to have a separate Square class that does not inherit from Rectangle but implements its own methods to calculate area, perimeter, etc.
Similarly, we could have in the case of a Student application which manages different types of student instances. Each instance of this object which could include a PartTime Student, Full-Time Student should all be able to function as the Superclass – Student from which they inherit.
Interface Segregation Principle (ISP):
Then we have The ISP, and this principle states that no client (classes that implements an interface) should be forced to depend on methods it does not use. This principle ensures that interfaces are focused and not bloated with unnecessary methods.
For example, consider a class called Printer. If we have a single method called print() that prints a document, this method may be overloaded with many parameters that may not be relevant for every client. Instead, we can split the Printer interface into smaller, more focused interfaces such as PrintDocument, ScanDocument, and CopyDocument. This way, clients can choose which interfaces they want to implement and use only the methods they need.
Dependency Inversion Principle (DIP):
And lastly, we have the DIP which states that high-level modules should not depend on low-level modules, but both should depend on abstractions. In other words, the DIP aims to reduce coupling between modules and increase their modularity and flexibility. By depending on abstractions rather than concrete implementations, modules can be easily replaced, extended or modified without affecting other modules in the system.
In practice, this means that we should strive to define abstract interfaces or classes that describe the functionality that our modules need, and then implement those interfaces in concrete classes or modules. The high-level module will then depend only on the abstract interface, and not on any concrete implementation details.
For example, let’s say we have a payment system that currently uses PayPal as its payment processor. If we hard-code the implementation details of PayPal into the payment system, it will be difficult to switch to a different payment processor if needed. However, if we define an abstract payment interface that describes the basic operations that our payment system needs (such as “charge” and “refund”), and then create a concrete PayPalPayment class that implements this interface, our payment system can depend only on the abstract payment interface. If we decide to switch to a different payment processor, we can simply create a new class that implements the same interface, and swap it in without changing the payment system’s code.
In conclusion, SOLID principles are crucial for writing maintainable and scalable code. By applying these principles, we can create flexible and modular code that is easy to extend and adapt to changing requirements.