Click here to Skip to main content
Click here to Skip to main content
Go to top

Understand Liskov Substitution Principle (LSP)

, 20 May 2013
Rate this:
Please Sign up or sign in to vote.
This Article will help you to make a clear understanding of LSP

Introduction 

Here I am going to discuss the Liskov’s Substitution Principle of SOLID . Now what does SOLID means ? SOLID is 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 SOLD .

 
  1. Understand Open Closed Principle and Dependecy Inversion .   
  2. Understand Single Responsibility and Interface Segregation  

Using the code 


Before start 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 is tough to understand ?  Ok making 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 understand. If you read articles related 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 start technical discussion look at the below picture and answer the questions. 

                                             

Fig : 1                                          

Question : Square is a Rectangle ?

Answer ; Yes

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
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 for every thing is ok .Now we will calculate the area of the Fig:1 Rectangle and Square.

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 out put of the  r.getArea(); method . Yes very simple the expected output is

7 * 3=21 . Ok now run the program with the below RectangleFactory() method and see did we get our expected result or not ? 
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 return.

Did you see the result? Yes its

This is the out put        

                 9

So Whats 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 Lets see
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 behviour here by assigning the height to Rectangle _width 
                        
    } 

Width=Height is must be rule for  Square not for  Rectangle .So when Square object returns from Rectanglefactory() before calling getAraa() user assigns r.SetHeight(3) and r.SetWidth(7) and waiting for a result 21 but getting 9It 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. Lets introduce another class

public class Quadrilaterals
{
    public virtual int Height { get; set; }
    public virtual int Width { get; set; }
    public int getArea()
    {
        return Height * Width;
    }
} 

Now change the inheritance hierarchies  by making it base class.

 

public class Rectangle :Quadrilaterals
{
    
    public override int Width
    {
        get { return base.Width; }
        set { base.Width = value; }
    }
    public override int Height
    {
        get { return base.Height; }
        set { base.Height = value; }
    }   
    
} 

 public class Square : Quadrilaterals  // In an "is a" relationship, the derived class is clearly a
                                      //kind of the base class
{
    public override int Height
    {
        get { return base.Height; }
        set { SetWidthAndHeight(value); }
    }

    public override int Width
    {
        get { return base.Width; }
        set { SetWidthAndHeight(value); }
    }

    private void SetWidthAndHeight(int value)
    {
        base.Height = value;
        base.Width = value;
    }
} 

 Now our factory method also changes .

 public Quadrilaterals QuadrilateralsFactory()
    {
        return new Square();
    }
    public void AreaOfQuadrilateral()
    {
        Quadrilaterals r = QuadrilateralsFactory(); // Returns the Quadrilaterals type object
        r.Height=7;
        r.Width=3;
        r.getArea();
    } 

Points of Interest 

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

 Quadrilaterals r = new Rectangle();
        r.Height=7;
        r.Width=3;
        r.getArea();

        Quadrilaterals r = new Square();
        r.Height = 7;
        r.Width = 3;
        r.getArea(); 

 Now user getting the expected behavior from the program. So Satisfy Liskov Substitute  Principle (LSP)

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Faisal(mfrony)

Bangladesh Bangladesh
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
 
LinkedIn
http://www.linkedin.com/profile/view?id=106671466&trk=tab_pro

Comments and Discussions

 
GeneralNicely explained! PinmemberShahdat Hosain10-Nov-13 13:01 
GeneralMy vote of 3 PinmemberSilvabolt16-Oct-13 3:58 
SuggestionExplaining LSP by sacrificing POLA principle. [modified] PinprofessionalRyszard Dżegan8-Sep-13 22:59 
GeneralRe: Explaining LSP by sacrificing POLA principle. [modified] PinmemberVikasChaturvedi11-Jun-14 21:43 
GeneralMy vote of 5 PinprofessionalMohammed Hameed22-May-13 19:17 
QuestionI see where you are going but... PinmemberMarkRHolbrook22-May-13 8:38 
BugNot a good example of Liskov Pinmembercjcordova22-May-13 7:51 
GeneralMy vote of 3 PinmemberPaulo Zemek21-May-13 10:23 
QuestionThis is wrong. PinmemberPaulo Zemek21-May-13 8:58 
AnswerRe: This is wrong. PinmemberFaisal(mfrony)21-May-13 14:28 
GeneralRe: This is wrong. PinmemberPaulo Zemek21-May-13 15:17 
GeneralRe: This is wrong. PinmemberFaisal(mfrony)21-May-13 15:30 
AnswerRe: This is wrong. PinmemberFaisal(mfrony)21-May-13 15:20 
GeneralExplained here PinmemberRaviBattula21-May-13 0:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140922.1 | Last Updated 21 May 2013
Article Copyright 2013 by Faisal(mfrony)
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid