DEV Community

Naomi Dennis
Naomi Dennis

Posted on

A Light Introduction Liskov Substitution Principle

The Liskov substitution principle, is the L in SOLID principles. It was created by Barbara Liskov and states:

Subtypes must be able to substitute base types.

Aside from the obvious implementation of this principle -- ensuring the subtype has the same behavior as the base type -- the implicit implementation is ensuring the subtype has the same semantic behavior as the base type.

Semantic is defined as:

Relating to meaning in language or logic.

And so, we create a definition of what the class name means. Typically, squares and rectangles are defined through their mathematic definition. Mathematically, a square is a shape with four sides in equal lengths. For rectangles, we will be using the definition of a perfect rectangle, meaning a shape where the top and bottom sides have equal lengths and left and right sides have equal lengths.

From this definition, we can conclude that a square's width and height must be the same while a rectangle can have a width different from its height as well as having a width equal to its height.

Let's create classes for these shapes, where we just define the width and height.

We can see that a Square object can easily replace a Rectangle object in a given situation. All Square objects share the same behavior as Rectangle.

However, we can see the semantic difference, when we test #area().

Because a rectangle can have a different height than its width the result of #area() adheres to our semantic definition.

If we replaced Rectangle with Square the test will pass, but the Square object is no longer behaving the way we expect.

Because a square's width and height cannot be different, the Square object breaks our semantic definition. This breaks the Liskov substitute principle.

The easiest way to ensure both Rectangle and Square pass the test, while satisfying LSP, is to remove line 4.

You may be thinking, why not implement a #setWidth() function in Rectangle that can be overwritten in Square? This would cause Square to only share the interface of Rectangle instead of its behavior, making the abstraction unnecessary. By removing line 4, we can satisfy LSP and we can go even further by making width and height private.

In Conclusion

When implementing inheritance, be sure to adhere to the meaning of the class outside of the implementation. This helps the class become more understandable in the grand scheme of the project.

Another technique that helps ensure classes adhere to LSP is design by contract.

Top comments (0)