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.