Click here to Skip to main content
11,705,119 members (42,041 online)
Click here to Skip to main content

Understand Liskov Substitution Principle (LSP)

, 20 May 2013 CPOL 35.7K 35
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

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun1-May-15 0:00
memberHumayun Kabir Mamun1-May-15 0:00 
GeneralNicely explained! Pin
Shahdat Hosain10-Nov-13 13:01
memberShahdat Hosain10-Nov-13 13:01 
GeneralMy vote of 3 Pin
Silvabolt16-Oct-13 3:58
memberSilvabolt16-Oct-13 3:58 
SuggestionExplaining LSP by sacrificing POLA principle. Pin
Ryszard Dżegan8-Sep-13 22:59
professionalRyszard Dżegan8-Sep-13 22:59 
GeneralRe: Explaining LSP by sacrificing POLA principle. Pin
VikasChaturvedi11-Jun-14 21:43
memberVikasChaturvedi11-Jun-14 21:43 
GeneralMy vote of 5 Pin
Mohammed Hameed22-May-13 19:17
professionalMohammed Hameed22-May-13 19:17 
QuestionI see where you are going but... Pin
MarkRHolbrook22-May-13 8:38
memberMarkRHolbrook22-May-13 8:38 
BugNot a good example of Liskov Pin
cjcordova22-May-13 7:51
membercjcordova22-May-13 7:51 
GeneralMy vote of 3 Pin
Paulo Zemek21-May-13 10:23
memberPaulo Zemek21-May-13 10:23 
QuestionThis is wrong. Pin
Paulo Zemek21-May-13 8:58
memberPaulo Zemek21-May-13 8:58 
AnswerRe: This is wrong. Pin
Faisal(mfrony)21-May-13 14:28
memberFaisal(mfrony)21-May-13 14:28 
GeneralRe: This is wrong. Pin
Paulo Zemek21-May-13 15:17
memberPaulo Zemek21-May-13 15:17 
GeneralRe: This is wrong. Pin
Faisal(mfrony)21-May-13 15:30
memberFaisal(mfrony)21-May-13 15:30 
AnswerRe: This is wrong. Pin
Faisal(mfrony)21-May-13 15:20
memberFaisal(mfrony)21-May-13 15:20 
GeneralExplained here Pin
RaviBattula21-May-13 0:02
memberRaviBattula21-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 | Terms of Use | Mobile
Web02 | 2.8.150819.1 | Last Updated 21 May 2013
Article Copyright 2013 by Faisal(mfrony)
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid