SOLID Design — Liskov Substitution Principle

Lucas PenzeyMoog
Sep 6, 2018 · 3 min read

In part three of my series describing Robert Martin’s SOLID principles, I’ll be describing the “L” in SOLID: the Liskov Substitution Principle. This is named after Barabra Liskov, who first stated the principle in her 1994 paper A Behavioral Notion of Subtyping:

Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.

That’s a bit…dense, so let’s break it down into more understandable terms. Robert Martin describes the principle in the following way:

Subtypes must be substitutable for their base types.

That’s a bit easier to understand. What it means is that you should be able to substitute a subclass with its parent class without affecting functionality from the user’s point of view. In short, the Liskov Substitution Principle makes sure that we’re implementing inheritance correctly.

Figure 1. from The Liskov Substitution Principle

The classic example for this principle is that of a Square class and a Rectangle class, so let’s implement those for our code example.

Martin explains that inheritance should be an “is a” type of relationship, meaning that since a square “is a” rectangle, our Square class should inherit from the parent Rectangle class.

“…if a new kind of object can be said to fulfill the ISA relationship with an old kind of object, then the class of the new object should be derived from the class of the old object.” -Robert Martin

Code Example

Below is a basic implementation of a Square class that inherits from Rectangle. Area is calculated in the same way for both shapes, so it should be ok for Square to inherit that method.

However, the problem occurs when we try to calculate the area for a square. In a rectangle the height and width can be different values, which is why we have a getter and a setter for each value. This allows us to interact with Square in a way that creates some unintended consequences, as seen in the spec file below.

As you can see, when we run the spec file the second test fails. We expect it to caluclate are by multiplying width by height, which we had set to 20 and 10. Why then do we get 100 for the output, rather than 200 as expected?

In Square we set the width equal to the height in the first method, and then we set the height equal to the width in the second method, which makes sense geometrically. But this causes the second test to fail, since in line 23 square.width = 10 sets both the height and width to ten, overriding the previous setting of height to 20.

So although we can see why a square object could have an “is a” relationship with a rectangle parent, it violates the Liskov Substitution Principle because the same data results in different behaviors when we implement methods from the different classes. In order for our code not to violate LSP, the behavior would need to appear the same regardless of which class’ methods we use.

Lucas PenzeyMoog

Written by

Photographer, developer, writer, Crafter @ https://8thlight.com/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade