SOLID Design Principles – Liskov Substitution Principle (LSP)

 

Liskov Substitution Principle can be considered to be an extension of the Open / Closed principle which states the base class reference should be replaceable by the child class without changing the functionality.

LiskovSubstitutionPrinciple

Let us assume that we implemented a Rectangle class with height, width properties and getArea method. Alone it will function perfectly fine.

 

public class Rectangle
{
    protected double Width;
    protected double Height;

    public virtual void SetWidth(double width)
    {
        Width = width;
    }

    public virtual void SetHeight(double height)
    {
        Height = height;
    }

    public double GetWidth()
    {
        return Width;
    }

    public double GetHeight()
    {
        return Height;
    }

    public double GetArea()
    {
        return Height * Width;
    }
}

Now we would like to have a similar functionality for a Square as well, so instead on reinventing the wheel we will simply inherit from the Rectangle class and customize the functionality for a square.

public class Square : Rectangle
{
    public override void SetWidth(double width)
    {
        Width = width;
        Height = width;
    }
    public override void SetHeight(double height)
    {
        Width = height;
        Height = height;
    }
}

 

But now if we replace the reference of the parent class by the child class then we will not the correct area for the rectangle since we have change the core functions (setHeight, setWidth) to set the height and width to same value which is not true in case of rectangle. Hence we have violated the Liskov Substitution principle.

var rectangleAsRectangle = new Rectangle();
rectangleAsRectangle.SetHeight(40);
rectangleAsRectangle.SetWidth(60);

Console.WriteLine("Area of the rectangle = " +
AreaCalculator.CalculateArea(rectangleAsRectangle) + " where Height = " +
rectangleAsRectangle.GetHeight() + " and Width = " +
rectangleAsRectangle.GetWidth());

Output:

Area of the rectangle = 2400 where Height = 40 and Width = 60

Rectangle squareAsRectangle = new Square();
squareAsRectangle.SetHeight(40);
squareAsRectangle.SetWidth(60);

Console.WriteLine("Area of the rectangle = " +
AreaCalculator.CalculateArea(squareAsRectangle) +
" where Height = " +squareAsRectangle.GetHeight() +
" and Width = " + squareAsRectangle.GetWidth());

Output:

Area of the rectangle = 3600 where Height = 60 and Width = 60

It is clear that the Square type is not substitutable for the Rectangle. LSP states that we should be able to the child classes should be able to extend the base classes without changing their existing functionality and we are violating that in this implementation as our square class is changing the behavior of the rectangle class.

Generally speaking the non-substitutable code will break polymorphism.

We can fix this code by creating a class (Shape) from which both Rectangle and Square inherit from. So as we could see in the code below, we have created an abstract class shape with an abstract method GetArea.

public abstract class Shape
{
    public abstract double GetArea();
}

We will now inherit this class in Rectangle and Square and provide the individual implementation of GetArea.

public class Rectangle : Shape
{
    private double _height;
    private double _width;

    public double Height
    {
        get { return _height; }
        set { _height = value; }
    }

    public double Width
    {
        get { return _width; }
        set { _width = value; }
    }

    public override double GetArea()
    {
        return Height * Width;
    }
}

public class Square : Shape
{
    private double _sideLength;
    public double SideLength
    {
        get
        {
            return _sideLength;
        }
        set
        {
            _sideLength = value;
        }
    }

    public override double GetArea()
    {
        return SideLength*SideLength;
    }
}

We could use the Shape class to get the area of the shapes.

static void Main()
        {
            Shape shape = new Rectangle { Height = 40, Width = 60 };
            Console.WriteLine("Area of the rectangle shape = " + shape.GetArea());

            shape = new Square { SideLength = 40 };
            Console.WriteLine("Area of the square shape = " + shape.GetArea());

            Console.ReadLine();
        }

Output

Area of the rectangle shape = 2400

Area of the square shape = 1600

So now the parent class is substitutable by the child classes without changing any existing functionality and so we are not violating the Liskov Substitution Principle.

 

Find the complete source code for this post at googledrive or skydrive.

Any questions comments and feedback are most welcome.