Object Oriented Programming: Liskov substitution principle

Mohamed Foued Jenni
2 min readAug 8, 2021

--

In mathematics, a Square is a Rectangle. Indeed it is a specialization of a rectangle. The "is a" makes you want to model this with inheritance. However if in code you made Square derive from Rectangle, then a Square should be usable anywhere you expect a Rectangle. This makes for some strange behavior.

Liskov substitution principle

Substitutability is a principle in object-oriented programming stating that, in a computer program, if S is a sub-type of T, then objects of type T may be replaced with objects of type S (i.e., an object of type T may be substituted with any object of a sub-type S) without altering any of the desirable properties of the program (correctness, task performed, etc.). More formally, the Liskov substitution principle (LSP) is a particular definition of a sub-typing relation, called (strong) behavioral sub-typing, that was initially introduced by Barbara Liskov in a 1988 conference keynote address titled Data abstraction and hierarchy.

Example

Consider an application that uses the following class.

// Violation of Likov's Substitution Principle
class Rectangle {
protected int m_width;
protected int m_height;

public void setWidth(int width) {
m_width = width;
}

public void setHeight(int height) {
m_height = height;
}

public int getWidth() {
return m_width;
}

public int getHeight() {
return m_height;
}

public int getArea() {
return m_width * m_height;
}
}

class Square extends Rectangle {
public void setWidth(int width) {
m_width = width;
m_height = width;
}

public void setHeight(int height) {
m_width = height;
m_height = height;
}

}

class LspTest {
private static Rectangle getNewRectangle() {
// it can be an object returned by some factory ...
return new Square();
}

public static void main(String args[]) {
Rectangle r = LspTest.getNewRectangle();

r.setWidth(5);
r.setHeight(10);
// user knows that r it's a rectangle.
// It assumes that he's able to set the width and height as for the base
// class

System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
}
}

Back to our case, imagine you had SetWidth and SetHeight methods on your Rectangle base class; this seems perfectly logical. However if your Rectangle reference pointed to a Square, then SetWidth and SetHeight doesn't make sense because setting one would change the other to match it. In this case Square fails the Liskov Substitution Test with Rectangle and the abstraction of having Square inherit from Rectangle is a bad one.

Solution

It is based on delegation. Concretely, it means that each instance of Square uses an instance of Rectangle to "do the job". This instance is called delegate in the implementation.

--

--