Liskov Substitution Principle (LSP) | SOLID PRINCIPLES

Liskov Substitution Principle (LSP) 

 The Liskov Substitution Principle (LSP) states that objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program. In other words, if a class S is a subclass of class T, an object of type T should be replaceable with an object of type S without affecting the functionality of the program.

Example:


Consider a scenario with geometric shapes:


public class Rectangle

{

    public virtual int Width { get; set; }

    public virtual int Height { get; set; }


    public int CalculateArea()

    {

        return Width * Height;

    }

}


public class Square : Rectangle

{

    public override int Width

    {

        set { base.Width = base.Height = value; }

    }


    public override int Height

    {

        set { base.Width = base.Height = value; }

    }

}


In this case, the `Square` class inherits from `Rectangle`. However, this violates the Liskov Substitution Principle because replacing a `Rectangle` with a `Square` breaks the expected behavior of the `Rectangle` class.


**Adhering to LSP:**


To adhere to LSP, it's better not to use inheritance for the relationship between `Square` and `Rectangle`. Instead, both classes can inherit from a common interface or have a shared abstraction:



public interface IShape

{

    int CalculateArea();

}


public class Rectangle : IShape

{

    public virtual int Width { get; set; }

    public virtual int Height { get; set; }


    public int CalculateArea()

    {

        return Width * Height;

    }

}


public class Square : IShape

{

    public int Side { get; set; }


    public int CalculateArea()

    {

        return Side * Side;

    }

}



Now, both `Rectangle` and `Square` adhere to the Liskov Substitution Principle, as they implement a common interface (`IShape`) and can be used interchangeably where an `IShape` is expected without altering the correctness of the program.


Real-world example related to a system that manages various shapes.


**Violation of LSP:**


Suppose you have a `ResizableRectangle` class that inherits from a `Rectangle` class, and you want to maintain the aspect ratio when resizing:



public class Rectangle

{

    public int Width { get; set; }

    public int Height { get; set; }

}


public class ResizableRectangle : Rectangle

{

    public new int Width

    {

        get { return base.Width; }

        set

        {

            base.Width = value;

            base.Height = value; // Maintaining aspect ratio

        }

    }


    public new int Height

    {

        get { return base.Height; }

        set

        {

            base.Height = value;

            base.Width = value; // Maintaining aspect ratio

        }

    }

}


This violates the Liskov Substitution Principle because a `ResizableRectangle` doesn't behave as expected when treated as a regular `Rectangle`. Code expecting a `Rectangle` may encounter unexpected behavior due to the overridden properties in `ResizableRectangle`.


**Adhering to LSP:**


To adhere to LSP, you could use composition instead of inheritance, ensuring that the behavior of the base class is not altered:



public interface IResizable

{

    int Width { get; set; }

    int Height { get; set; }

}


public class Rectangle : IResizable

{

    public int Width { get; set; }

    public int Height { get; set; }

}


public class ResizableRectangle : IResizable

{

    private Rectangle rectangle = new Rectangle();


    public int Width

    {

        get { return rectangle.Width; }

        set

        {

            rectangle.Width = value;

            rectangle.Height = value; // Maintaining aspect ratio

        }

    }


    public int Height

    {

        get { return rectangle.Height; }

        set

        {

            rectangle.Height = value;

            rectangle.Width = value; // Maintaining aspect ratio

        }

    }

}


Now, both `Rectangle` and `ResizableRectangle` adhere to the Liskov Substitution Principle. Code expecting a `Rectangle` can work with a `ResizableRectangle` without unexpected side effects.

Comments