15,794,347 members
Articles / Web Development / ASP.NET

# Understand Liskov Substitution Principle (LSP)

Rate me:
4 Nov 2018CPOL3 min read 121.1K   46   22

## Introduction

Here, I am going to discuss the Liskov’s Substitution Principle of S<code>OLID. Now what does SOLID mean? SOLID is an object oriented design principle, where each letter has it own meaning:

• S-> Single responsibility
• O-> Open Closed
• L-> Liskov substitution
• I-> Interface segregation
• D-> Dependency inversion

According to Wikipedia, the definition of SOLID is:

"SOLID are guidelines that can be applied while working on software to remove code smells by causing the programmer to refactor the software's source code until it is both legible and extensible."

## Background

If you read my previous article, it will be very helpful for you to understand SOLID.

## Using the Code

Before starting with the technical discussion, I want to answer the below questions:

What is Liskov substitution principle?

Answer: "objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program"

Is my answer tough to understand? Ok, I will make it more easy...

"It means that we must make sure that new derived classes are extending the base classes without changing their behavior."

Let's consider an example to make it better understood. If you read articles related to the Liskov principle, one example is very popular. Yes that is Rectangular and Square. Here, I will show you the same but will try to explain each and every aspect clearly. Before starting with the technical discussion, look at the below picture and answer the questions.

Figure 1

Question: Is Square a Rectangle?

If you remember Inheritance, then the word "Is a" relationship familiar to you. So if I convert this to code, it looks like the following:

C#
public class Rectangle
{
protected int _width;
protected int _height;
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}

public virtual void SetWidth(int width)
{
_width = width;
}
public virtual void SetHeight(int height)
{
_height = height;
}
public int getArea()
{
return _width * _height;
}
}

public class Square : Rectangle  // In an "is a" relationship, the derived class is clearly a
//kind of the base class
{
public override void SetWidth(int width)
{
_width = width;
_height = width;
}

public override void SetHeight(int height)
{
_height = height;
_width = height;
}
}

So everything is ok. Now we will calculate the area of Figure 1: Rectangle and Square.

C#
public void AreaOfRectangle()
{
Rectangle r = RectangleFactory(); // Returns the rectangle type object
r.SetWidth(7);
r.SetHeight(3);
r.getArea();
}

So can you tell me the output of the r.getArea(); method. Yes, very simple, the expected output is 7 * 3=21. Now run the program with the below RectangleFactory() method and see whether we get our expected result or not?

C#
public  Rectangle RectangleFactory()
{
return new Square();
}

One thing I want to mention about the RectangleFactory() is that, this method is now exposed to you. But think as if you are getting the Rectangle object just by using a factory DLL or from any service where you have no idea what type of rectangle object will be returned.

Did you see the result? Yes.

This is the output: 9.

So what's wrong there ? Remember as I said earlier:

"we must make sure that new derived classes are extending the base classes without changing their behavior"

If we say specifically:

"we must make sure that Square classes are extending the Rectangle without changing their behavior"

Is the above sentence correct according to our program?

No, the problem is:

without changing their behavior

But we change the behavior of the base Rectangle class. Did you notice how? No, OK, let's see:

C#
public override void SetWidth(int width)
{
_width = width;
_height = width; //Change the behavior here by assigning the width to Rectangle _height

}

public override void SetHeight(int height)
{
_height = height;
_width = height;//Change the behavior here by assigning the height to Rectangle _width

}

Width=Height is must be rule for Square <code>not for Rectangle. So when Square object returns from Rectanglefactory() before calling getArea(), user assigns r.SetHeight(3) and r.SetWidth(7) and waits for a result 21 but gets 9. It changes the result. But the end user was expecting the result of Rectangle area.

So violation of Liskov substitution principle occurs.

Now the solution is to manage the class inheritance hierarchies correctly. Let's introduce another class.

C#
{
abstract public int GetArea();
}

Now change the inheritance hierarchies by making it base class.

C#
{
public int Width
{
get ; set ;
}
public int Height
{
get ;
set ;
}
public override int GetArea()
{
return Height * Width;
}
}
C#
public class Square : Quadrilaterals  // In an "is a" relationship, the derived class is clearly a
// kind of the base class
{
public  int Size
{
get ;
set ;
}
public override int GetArea()
{
return Size* Size;
}
}

Now our factory method also changes.

C#
{
return new Square();
}
{
r.Height=7;
r.Width=3;
r.getArea();
}

## Points of Interest

So from users point of view, now s/he is expecting the area of <code>Quadrilateral not the Rectangle. By using this input, when output comes 21 is a Rectangle area and when 9 it's a Square .

C#
r.Height=7;
r.Width=3;
r.getArea();

r.Height = 7;
r.Width = 3;
r.getArea();

Now user gets the expected behavior from the program. So it satisfies the Liskov Substitute Principle (LSP).

Written By
I am a Sr.Software Engineer at Brain Station -23. I have 5+ years of work experience in .Net technology. I strongly believe that before software can be reusable it first has to be usable.

My contact info :

mfrony2003@yahoo.com
mfrony2003@hotmail.com

 First Prev Next
 SOID dmjm-h5-Nov-18 14:04 dmjm-h 5-Nov-18 14:04
 Your example should be like this. Sanjay K. Gupta5-Nov-18 3:55 Sanjay K. Gupta 5-Nov-18 3:55
 Are you fitting square pegs into round holes? George Swan4-Nov-18 21:23 George Swan 4-Nov-18 21:23
 Although this is an update, the problems highlighted in the earlier comments do not appear to have been resolved. A rectangle has two independent variables, width and height, but a square only has one. So there is not enough commonality for the two classes to share a base class other than them both being Objects. If some synergy is required between the two classes, it could be achieved by having them implement an interface with just the single method GetArea(). It seems to me that a good way to ensure that this Liskov principle is not adhered to is to try and fit square pegs into rectangular holes.
 Simple and Well explained laxmeesh.joshi8-Mar-16 0:04 laxmeesh.joshi 8-Mar-16 0:04
 [My vote of 2] Good but... Nejimon CR1-Jan-16 2:44 Nejimon CR 1-Jan-16 2:44
 Re: [My vote of 2] Good but... Member 1379719924-Apr-18 23:45 Member 13797199 24-Apr-18 23:45
 Re: [My vote of 2] Good but... Paulo Zemek26-Jun-18 12:36 Paulo Zemek 26-Jun-18 12:36
 My vote of 5 Humayun Kabir Mamun1-May-15 1:00 Humayun Kabir Mamun 1-May-15 1:00
 Nicely explained! Shahdat Hosain10-Nov-13 14:01 Shahdat Hosain 10-Nov-13 14:01
 My vote of 3 Silvabolt16-Oct-13 4:58 Silvabolt 16-Oct-13 4:58
 Explaining LSP by sacrificing POLA principle. Ryszard Dżegan8-Sep-13 23:59 Ryszard Dżegan 8-Sep-13 23:59
 Re: Explaining LSP by sacrificing POLA principle. VikasChaturvedi11-Jun-14 22:43 VikasChaturvedi 11-Jun-14 22:43
 My vote of 5 Mohammed Hameed22-May-13 20:17 Mohammed Hameed 22-May-13 20:17
 I see where you are going but... MarkRHolbrook22-May-13 9:38 MarkRHolbrook 22-May-13 9:38
 Not a good example of Liskov charoco22-May-13 8:51 charoco 22-May-13 8:51
 My vote of 3 Paulo Zemek21-May-13 11:23 Paulo Zemek 21-May-13 11:23
 This is wrong. Paulo Zemek21-May-13 9:58 Paulo Zemek 21-May-13 9:58
 Re: This is wrong. Faisal(mfrony)21-May-13 15:28 Faisal(mfrony) 21-May-13 15:28
 Re: This is wrong. Paulo Zemek21-May-13 16:17 Paulo Zemek 21-May-13 16:17
 Re: This is wrong. Faisal(mfrony)21-May-13 16:30 Faisal(mfrony) 21-May-13 16:30
 Re: This is wrong. Faisal(mfrony)21-May-13 16:20 Faisal(mfrony) 21-May-13 16:20
 Explained here RaviBattula21-May-13 1:02 RaviBattula 21-May-13 1:02
 Last Visit: 31-Dec-99 19:00     Last Update: 4-Dec-23 10:51 Refresh 1