When extending a class, consider that you should be able to pass objects of the subclass in place of objects of the parent class without breaking the client code.
I've stated this principle informally; if you look it up on Wikipedia for instance, you will find formal descriptions such as
ϕ(x) be a property provable about objects
x of type
ϕ(y) should be true for objects
y of type
S is a sub-type of
All this, is a fancy way of saying that every subclass/derived class should be substitutable for their base/parent class. In other words, a subclass should not break the expectations (code contracts) set by its super-class.1
Let's see an example to better understand the Liskov Substitution Principle (LSP). Consider the following implementation of
Since a square is a rectangle (mathematically speaking), we decide to implement
Square as a subclass of
Rectangle. We override
setHeight and we can reuse the implementation of
With this overriding of
setHeight -- to set both dimensions to the same value -- instances of
Square remain mathematically valid squares.
The bad news is that making
Square a subtype of
Rectangle violates the Liskov Substitution Principle. Here is why:
LSP is violated because if we pass an object of
clientMethod (which we can since
Square is a subtype of
Rectangle) the assertion in
clientMethod will fail. In other words, the expected behavior of super type is not maintained.
So what is the solution? Well, you can simply make two separate classes:
You could use composition to reuse the code in
Case in point
- LSP is all about well-designed inheritance. If you cannot substitute your baseclass with a subclass without things going wrong, then it means you used inheritance incorrectly.
- Inheritance seems like a cool idea; you get to create a hierarchy of types and reuse your code. But, it’s easy to abuse inheritance. So, don't overdo it; especially consider composition over inheritance!