Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

The Liskov Substitution Principle – Agile Software Development Principles Patterns and Practices

For the past few weeks I have been doing a chapter-by-chapter review of Agile Software Development Principles, Patterns, and Practices by Robert Martin.  So far, it has covered a lot of good introductory information on various Agile Methodologies (Test-Driven Development, Refactoring, Pair Programming, Project Planning, Extreme Programming, etc.) as well as talked about various object-oriented programming principles, which is what I am still covering now.


Here is a chapter-by-chapter breakdown on what I have covered so far:


Agile Software Development, Principles, Patterns, and Practices

Book: Agile Software Development, Principles, Patterns, and Practices (Amazon)
Author: Robert C. Martin (Amazon)
Publisher: Prentice Hall; 1st edition (October 15, 2002)
Hardcover: 552 pages


Previous Chapters



 


Chapter 10 is on the Liskov Substitution Principle:


 


Liskov Substitution Principle

“What is wanted is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T. [Liskov88]“


 


Is it me, or is that painful to read?  Robert Martin puts it a bit simpler:


Subtypes must be substitutable for their base types


The classic example of this principle in code is inheriting the Square Class from the Rectangle Class.


 


Classic Example of LSP
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.  It will actually be 4 because “unexpectedly” in this case, both height and width are being set to each other when the width or height is set on a square.  Therefore, if this behavior by Square is unacceptable and unexpected, Square should not be a subclass of Rectangle (at least not coded like this with these expectations anyway).


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.  This is where unit tests can really be handy.  The unit tests essentially describe and test for the expected behavior of objects (design by contract, if you will).


If you want to read some discussions as to the usefulness of this principle, whether it should be a principle, and thoughts on the classic example above, check out this wiki.  You can also read what Robert Martin has to say about it from this PDF.

This entry was posted in Design Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>