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
Post a Comment