LSP: Liskov Substitution Principle
This principle was named after Barbara Liskov, who defined it in 1987 in her work Data abstraction and hierarchy.
Introduction
The Liskov Substitution Principle is one of 5 principles of Object-Oriented Design. They are :
- Single Responsibility Principle
- Open-Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
In this post, I will focus on LSP, and I will explain the other principles in future articles.
Definition
Uncle Bob defines the principle as:
Subtypes must be substitutable for their base types.
A Superclass object should be replaceable with a Subclass object without breaking the functionality of the software.
The Substitution Principle is a set of checks that helps predict whether a class will still compatible with code that worked with parent class objects. This concept is critical when you are developing libraries and frameworks.
Using this principle, the code should not depend on the class hierarchy. Therefore, it should not use a cast or an “instanceof” operator.
This principle imposes some rules on subclasses, and more specifically on their methods.
Rules
Let’s look at some of this rules in details:
- Method parameters types
Subclass method parameter types must match or be more abstract than parent class method parameter types.
- Method return type
The return type in a method of a subclass must match or be a subtype of the return type of the parent class method.
As you can see, the pre-requirements for a method’s return types are the inverse of the parameter types.
- Precondition
A subclass should not enforce preconditions.
There are other rules like:
- A subclass should not weaken postconditions.
- The invariants of a parent class must be preserved.
- A subclass should never modify the values of the private attributes of a parent class (using Reflection).
- A method in a subclass should not throw the types of exceptions that the base method is not supposed to throw.
For more, check this article: https://www.baeldung.com/java-liskov-substitution-principle
Example
We have a class called Bird which contains two methods: Eat and Fly. We start writing code and create a Canary class and an Ostrich class that both inherit from Bird.
Let’s analyze this code, you will immediately notice that there is a problem. Ostriches cannot fly and yet they are birds too like Canari.
Two Questions:
Can the Bird be replaced by a Canary in all cases? ⇒ Yes
Can the Bird be replaced by an Ostrich in all cases? ⇒ No because of the fly method throwing an exception that the parent class Bird does not.
So Let’s correct this:
To solve this and implement the LSP, just create an intermediate class to differentiate this behavior.
We are therefore going to set up a class FlyingBird that will inherited by the Canary class.
The Ostrich class still inherit from Bird that contains now only the eat method.
Conclusion
The LSP enables you to replace objects of a parent class with objects of a subclass without breaking the application.
Thank you for reading this quick post. If you like the content feel free to follow me on my social media profiles. Thank you.
Twitter: https://twitter.com/HBenkachoud
Linkedin: https://www.linkedin.com/in/hicham-benkachoud/