
Liskov Substitution Principle in SOLID
Author - Abdul Rahman (Bhai)
SOLID
6 Articles
Table of Contents
What we gonna do?
In this article, let's learn about Liskov Substitution Principle in SOLID Principles in .NET.
Note: If you have not done so already, I recommend you read the article on Open Closed Principle in SOLID.
The Liskov Substitution Principle (LSP), which has been around since 1987. The LSP is a fundamental principle of object-oriented programming and is part of the SOLID principles. LSP states that objects in a program should be replaceable with instances of their subtypes without altering the correctness of the program. In other words, if class B is a subtype of class A, then objects of type B should be able to be used wherever objects of type A are expected, without causing any unexpected behavior or violating any contracts.
Why we gonna do?
Without LSP, a subclass that overrides base class behavior in unexpected ways can break the code that depends on the base class contract. Callers that assume a Vehicle can be started with a key will encounter broken behavior if a subclass silently ignores or throws on that operation. This violates the trust that polymorphism is built on.
Adhering to LSP ensures that your class hierarchies are reliable and that polymorphism works correctly. Any code written against a base type continues to work when given a subtype, making the system predictable, easier to extend, and safer to maintain.
How we gonna do?
When to apply LSP?
Use the Liskov Substitution Principle when you have a class hierarchy, and you want to ensure that subclasses can be used interchangeably with their superclass. It is particularly useful when working with interfaces or abstract classes that define contracts for behavior, allowing different implementations to be used seamlessly.
Demo
Suppose we have a base class called Vehicle, which has a method Move() that receives a key to start the vehicle. We also have a subclass called Truck, which inherits from Vehicle. Both classes have a method with the same signature, but their implementations may differ.
public class Vehicle
{
public virtual void Move(string key)
{
// Implementation to start the vehicle
}
}
public class Truck : Vehicle
{
public override void Move(string key)
{
// Implementation specific to trucks
}
}
The Liskov Substitution Principle ensures that we can replace an instance of Truck with an instance of Vehicle and still expect the same behavior. Let's see how this works:
Vehicle vehicle = new Truck();
vehicle.Move("start");
Even though the Vehicle object is of type Truck, we can treat it as an instance of Vehicle and call the Move() method. This demonstrates the substitutability aspect of the Liskov Substitution Principle.
Advantages
The Liskov Substitution Principle has several advantages, including:
- Code Reusability: Create a hierarchy of classes that can be easily reused in different contexts. Subclasses can be substituted for their base class, allowing for flexible and extensible code.
- Polymorphism: Objects of different types can be treated uniformly through a shared interface or base class. This promotes code flexibility and simplifies interactions between objects.
- Modularity and Maintainability: Helps in creating modular code structures that are easy to understand and maintain. It allows developers to focus on specific behaviors in subclasses while ensuring compatibility with the base class.
- Testability: Promotes testability by allowing you to write meaningful and focused tests for individual classes or interfaces. Subclasses can be tested independently, and their behavior can be validated without relying on the specifics of the base class.
Summary
The Liskov Substitution Principle is a fundamental principle in object-oriented programming that ensures substitutability of objects in a hierarchy. It emphasizes that subclasses should be able to substitute their base class without affecting the correctness of the program.
By adhering to the LSP, you create code that is reusable, extensible, and easily maintainable. It promotes modularity and allows for polymorphic behavior, where objects of different types can be treated uniformly. The LSP also improves testability by enabling focused testing of individual classes or interfaces.