# SOLID Principles by Examples: Liskov Substitution Principle

### This post analyzes the Liskov Substitution Principle (LSP), one of the SOLID principles of programming, and how it makes your code more reusable and less coupled.

· DevOps Zone · Analysis
Save
15.77K Views

In this post, we're going to explore the third of the SOLID principles: the Liskov Substitution Principle (LSP).

The most practical definition of this principle was written by Robert C. Martin in his book, "Agile Software Development, Principles, Patterns, and Practices:" "Subtypes must be substitutable for their base types."

The concept was introduced by Barbara Liskov in 1987. The formal definition is: "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."

For our daily activities, we must remember that a subclass should override the parent class's methods in a way that doesn't break functionality from a consumer's point of view.

## Example

``````abstract class MusicalInstrument
{
public abstract void PlayANote();
}

class Piano : MusicalInstrument
{
public override void PlayANote()
{
PressKey();
}

private void PressKey()
{
//Press a piano key.
}
}

class Saxophone : MusicalInstrument
{
public override void PlayANote()
{
Blow();
}

private void Blow()
{
//Blow air into the instrument.
}
}``````

## The Evergreen Example

To better understand LSP, let's examine this classic example. It's a classic because it's easy to understand and very meaningful. We start with this question: Is a square a special rectangle in OOP?

We try to answer this question with this simple class hierarchy: a Rectangle as the base class and a Square class that inherits from it. In the Square class, we override the behavior of the setters to enforce that the Height and Width properties have the same value.

``````class Rectangle
{
public virtual float Heigth { get; set; }
public virtual float Width { get; set; }
public virtual float Area
{
get { return Heigth * Width; }
}
}

class Square : Rectangle
{
private float _heigth;

private float _width;

public override float Heigth
{
get
{
return _heigth;
}
set
{
_heigth = value;
_width = value;
}
}

public override float Width
{
get
{
return _width;
}
set
{
_width = value;
_heigth = value;
}
}
}``````

Now we have to remember that a subclass must override the base class in a way that it doesn't break functionality from a client's POV. We write these two tests to check.

``````[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestWithRectangle()
{
Rectangle sut = new Rectangle();
sut.Heigth = 3;
sut.Width = 7;

Assert.AreEqual(21, sut.Area);
}

[TestMethod]
public void TestWithSquare()
{
Rectangle sut = new Square();
sut.Heigth = 3;
sut.Width = 7;

Assert.AreEqual(21, sut.Area); //This test will fail. Area equals 49.
}

}``````

So it's clear that in OOP, a square isn't a particular case of a rectangle. How can we do to better organize these classes? The typical approach consists of creating an abstract class (or an interface). For example:

``````abstract class Shape
{
public abstract float Area { get; }
}

class Rectangle : Shape
{
public float Heigth { get; set; }
public float Width { get; set; }
public override float Area
{
get { return Heigth * Width; }
}
}

class Square : Shape
{
public float Edge { get; set; }

public override float Area
{
get { return Edge * Edge; }
}
}``````

Now our code states that both the Rectangle class and the Square class are Shapes, which is true. Our code is also safer and we don't have any situation where a client will receive unexpected values.

## TL;DR

In this post, we explored the Liskov Substitution Principle (LSP) and we learned that it's not true that real-life objects always maps to the same OOP structure/class ecosystem. We also tried to improve the wrong example with the simple technique of adding an abstraction layer (the Shape class).