What a title to put an article on it, but after reading about that principle I had that feeling that sharing it will benefit someone out there.
that principle is talking about Good practice in Object-Oriented software Design and its definition is the following:
FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE
CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES
WITHOUT KNOWING IT.
What does that mean in simple words?
If you have the following class diagram (I will rely on a function in the base class instead of providing a new class for the purpose of demonstrating) :
in that diagram you have a hierarchy for the brush classes that include a base abstract class called “Brush” and inherited from it the “Solid”, “Gradient” and the “Texture”
In the “Brush” class we have one method which draw on the supplied “surface” argument using the brush’s attributes, and in our case we have that code that do the drawing:
public void Draw(Graphics surface)
{
if (this is Solid)
{
// draw with solid color
}
else if (this is Gradient)
{
// draw a gradient
}
else if (this is Texture)
{
// draw with a texture bitmap
}
}
That Code is a very bad practice and will definitely lead to serious problems later on when you need to add more classes that inherit from the base “Brush” class.
think of what will you do if you have 20 types of brushes ?? what about a 100 or 200 types ?? , maybe in that particular example the real world does not offer that amount of brushes .. but for demo purpose you should think of what that method/function will look like if you have hundreds of inherited classes of the base “Brush’” class ……. Exactly yes it will be a big mess and maintaining that method will be a headache later when that application evolves.
So what should we do about it ???
the best solution here in my opinion is to rely on inheritance and the magical “Virtual / Override” mechanism
so our first best practice here is to distribute that function’s responsibility to the class hierarchy and leave it “open for extensibility but closed for modifications” as the best practices say.
and here is the new diagram after fixing it:
and the code for the base class will be as following:
public virtual void Draw(Graphics surface)
{
// draw on the surface
}
Note the “Virtual’ operator that decorates our function definition, that means that our inherited classes are free to “Override” this particular method and/or extend it with new or different logic or behavior
and here is the code in the descendant classes:
public class Texture : Brush
{
public override void Draw(System.Drawing.Graphics surface)
{
// we can use the next statement to call the parent’s draw method
base.Draw(surface);
// extend the drawing with a concrete Texture Brush
}
}public class Solid : Brush
{
public override void Draw(System.Drawing.Graphics surface)
{
// create a very different logic for the brush and do not use the parent’s code
}
}
as we can see that “Texture” executed “base.Draw(surface)” before it proceeds with its own logic and that means that it will let the parent do its work first and then it will complete hereafter it with its own logic, and in the “Solid” it never called its Base/parent and it will provide a totally different logic for the drawing.
Final Note
one more thing here for you to note is that you need to watch out for changes you will provide in behavior because in “Design by contract” principle you MUST preserve all logic and validation that is expected from the parent class in all its children and you should not alter the default parent behavior unless it is not going to break any of its client’s usages.
such as if the Draw method is supposed to Fire an Event after finishing the drawing, any of its descendants when they override that method MUST fire that event no matter what they do because the other classes will rely on that event to do other related logic.

[...] The Liskov Substitution Principle (LSP ) October 2009 4 [...]
Pingback by 2010 in review « Maximum C# — January 2, 2011 @ 1:24 PM