Liskov Substitute Principle (LSP) with Code example


Basically when we designed a class, we use maintain Class hierarchies. We must make sure that the new derived classes just extend without replacing the functionality of old classes. Otherwise the new classes can produce undesired effects when they are used in existing program modules.

LSP states that if the module using any base class, then the reference to the Base class can be replaced with a Derived class without affecting the functionality of the program module.

Example : - A typical example that violates LSP is a Square class that derives from a Rectangle class, assuming getter and setter methods exist for both width and height. The Square class always assumes that the width is equal with the height. If a Square object is used in a context where a Rectangle is expected, unexpected behavior may occur because the dimensions of a Square cannot (or rather should not) be modified independently. This problem cannot be easily fixed: if we can modify the setter methods in the Square class so that they preserve the Square invariant (i.e. keep the dimensions equal), then these methods will weaken (violate) the postconditions for the Rectangle setters, which state that dimensions can be modified independently. If Square and Rectangle had only getter methods (i.e. they were immutable objects), then no violation of LSP could occur.

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 class Square: Rectangle

{

    public override void SetWidth(int width)

    {

        _width = width;

        _height = width;

    }

    public override void SetHeight(int height)

    {


        _height = height;


        _width = height;
    }
}

[TestFixture]

public class RectangleTests

{
    [Test]

    public void AreaOfRectangle()

    {
        Rectangle r = new Square();

        r.SetWidth(5);

        r.SetHeight(2);

         // Will Fail â€" r is a square and sets

        // width and height equal to each other.
        Assert.IsEqual(r.Width * r.Height,10);

    }
}

 

If you look at the test above, it will fail because a square is being substituted for a rectangle and the area won't be 10 as expected.  This is the whole point of the Liskov Substitution Principle.  It basically wants you to think clearly about the expected behavior and expectations of a class before you derive new classes from it.  It could turn out that when subclasses are substituted for a base class, you may get unexpected results. 


Similar Articles