Sunday, May 10, 2009

The Liskov Substitution Principle in C#.Net (LSP in C#.Net)




The Liskov Substitution principe was coined by Barber Liskov in her work regarding data abstraction and type theory. In simple english the principle can be stated as
“ Any derived class should be substitutable for their base classes”
That is, a user of a base class should continue to function properly if a derivative of that base class is passed to it.
Let us say consider the above example. “SavingsWithDrawform” class has a method which accepts the “Accounts” class object as shown below.
public void WithDraw( Accounts objAcc)
{
//Code Implementation of Account objects
}
The principle of LSP states that it should be legal to pass the the “SavingsAccount” object to the same method, which is as shown
public void WithDraw(SavingsAccounts objAcc)
{
//Passing the derived type should be legal
}

This looks prety obvious. But let us consdier the follwing code example
Let us say we have rectangle class with the following code
public class Rectangle
{
protected int _Height;
protected int _Width;

public int Height
{
get { return _Height; }
}


public int Width
{
get { return _Width; }
}

public virtual void SetHeight(int intHeight)
{
_Height = intHeight;
}
public virtual void SetWidth(int intWidth)
{
_Width = intWidth;
}
}
Now let say we have one more class which is derived from “Rectangle” class is Square class
public class Square:Rectangle
{
public override void SetHeight(int intHeight)
{
_Width = intHeight;
_Height = intHeight;
}
public override void SetWidth(int intWidth)
{
_Height = intWidth;
_Width = intWidth;
} }


Now let say you have a method to calculate area and below is the code for this
Rectangle objRect = new Square();

objRect.SetHeight(2);
objRect.SetWidth(5);

int area = objRect.Width * objRect.Height;

When the area is calcualted it will show as 25, but actually we have expected the value to be 10. So here in this case the derived class is not substitutable for the base class.
References
http://www.objectmentor.com/resources/articles/lsp.pdf

1 comment:

Efim Zabarsky said...

From the other side, bad abstraction created because bad knowledge of Geometric aspect: square is-a rhombus (with angle = 90 degree), not is-a rectangle.

So, in C# i get:

abstract class Romb : GeometricFigure
{
public double SideLength { get; set; }
public double Angle { get; set; }
public Romb(double sideLength, double angle)
{
SideLength = sideLength;
Angle = angle;
}
public double Area()
{
return Math.Pow(SideLength, 2) * Math.Sin(Angle);
}
}
class Square : Romb
{
public Square(int sideLength)
: base(sideLength, 90)
{
}
}
What do you think about it?