To adhere to LSP, subclasses should not:
Let's illustrate LSP with an example involving shapes.
Consider a base class Rectangle and a derived class Square.
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double Area()
{
return Width * Height;
}
}
public class Square : Rectangle
{
public override double Width
{
get { return base.Width; }
set
{
base.Width = value;
base.Height = value;
}
}
public override double Height
{
get { return base.Height; }
set
{
base.Height = value;
base.Width = value;
}
}
}
In this example, the Square class violates LSP because it changes the behavior of the Width and Height properties, causing the Rectangle's expectations to be violated. When a Square object is used in place of a Rectangle, the behavior is not as expected.
To adhere to LSP, we need to ensure that the behavior of derived classes does not break the expectations set by the base class. One way to achieve this is by using interfaces or by redefining the class hierarchy to better represent the problem.
public abstract class Shape
{
public abstract double Area();
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area()
{
return Width * Height;
}
}
public class Square : Shape
{
public double Side { get; set; }
public override double Area()
{
return Side * Side;
}
}
In this refactored design, Rectangle and Square both inherit from Shape and implement the Area method. This way, each class adheres to the expectations set by the base class, and using a Square in place of a Shape will not violate LSP.