
Not everything is what it appears to be with first sight, and while the below image is pretty obvious for most of us, there are more subtle places where it can be difficult to determine. Especially in our profession as developers. LSP is one of the notoriously most difficult places to understand, even though the principle by itself is simple. I guess it all comes down to the most difficult question man have ever asked; to be or not to be, that's the question...
LSP or the Liskov Substitution Principle basically says that a class must fulfill an "is-a-relationship" in order for it to be able to inherit from another class. This means that if you are supposed to inherit a new class from some already existing class then the new class *must* be in a perfect "is-a-relationship" with the class you're inheriting from. The school example of this is a Square and a Rectangle.
The Square and Rectangle problem
Most people would think that a Square is a special kind of Rectangle and therefor intuitively inherit their Square class from the Rectangle class to be able to reuse code. However if you study the above image you will notice that the Rectangle have a couple of traits that the Square does NOT and vice versa. First of all the Square has only *ONE* attribute; size, while the Rectangle have *TWO* attributes; width & height. And this fact may for some problems be quite tricky to discover sometimes. And if you do the capital sin of inheriting your Square class from your Rectangle class, then you might currently get around it by hiding the width property of the Rectangle somehow, maybe by convention, and then just let the size property of the Square forward the call to height or something similar, but this is always wrong!
First of all problems like that tends to "leak" which means that when some other guy comes around and wants to reuse your code he doesn't realize that there's a problem to it and he starts using the width instead of the height or size property and doesn't understand why this doesn't work - and you've got yourself a perfect leaking abstraction!
Now in some programming languages there does actually exist ways to "fix this", namely C , through Policy Based Design you can actually (though it is VERY hard) inherit only "partially" and thereby only inheriting parts of the implementation of the Rectangle class through using "Magic Enums" which I wrote about almost 10 years ago, but that's way out of scope for this article. And for most programming languages (C# and Java for instance) you don't have tricks like that up your sleeves to "fix" LSP...
The problem is when you hit "real life scenarios", especially with Single Inheritance programming languages - like for instance C# and Java. Because if you're not supposed to break LSP you will often tend to repeat code a LOT. In C# you cannot inherit from multiple classes like you can in C and other MI (Multiple Inheritance languages) you cannot create "small, lightweight carrier classes" for you to inherit from to not break LSP. This really sucks, and Anders - if you're reading this - we REALLY need MI on the CLR!
There exists a common design pattern here to help you though.
Outfactored Implementation Classes
And "outfactored implementation class" is when you'd "like" to inherit from multiple classes but you're in a single inheritance programming language. What you can often do is to create a bunch of interfaces coupled with concete classes which are their implementation. Then in the classes you wish to use Multiple Inheritance within you can implement those interfaces and have a very thin forward call to the concrete "composition" class which implements that interface. It ends up being FAR more messy than the "pure" Multiple Inheritance solution, but until Anders Hejlsberg and Co or the Java guys decides to gives us a *really* useful feature (hint; MI) it's the best we can get - unless we want to switch back to C again...
Let's show some (pseudo) code;
class Jedi {/*...*/}
class Sith {/*...*/}
class LightningHands {/*...*/}
class JediKnight : Jedi {/*...*/}
class SithKnight : Sith {/*...*/}
class JediMaster : Jedi, LightningHands {/*...*/}
class SithMaster : Jedi, LightningHands {/*...*/}
You see the problem...?
Without Multiple Inheritance we CANNOT do the above thing unless we turn the LightningHands into an *interface*. And we don't really want to do that since we have a lot of functions in the LightningHands class like "fly", "throw lightning out of our hands" and so on. And this is functionality we'd like to REUSE!
Though there's a neat little trick to the rescue for us here ;)
class Jedi {/*...*/}
class Sith {/*...*/}
class LightningHands
{
void ThrowLightning()
{
/*...*/
}
}
// NEW code
interface ILightningHands
{
void ThrowLightning();
}
class JediKnight : Jedi {/*...*/}
class SithKnight : Sith {/*...*/}
class JediMaster : Jedi, ILightningHands
{
private LightningHands _lightning;
void ThrowLightning()
{
// Implementation of interface method
// Just "forwarding" to composition object
_lightning.ThrowLightning();
}
}
class SithMaster : Jedi, ILightningHands
{
private LightningHands _lightning;
void ThrowLightning()
{
// Implementation of interface method
// Just "forwarding" to composition object
_lightning.ThrowLightning();
}
}
And with this neat little trick we can get to reuse the code in LightningHands and "pretend" that it's actually used through inheriting directly from LightningHands, though at the cost of forward calling every single method call to our composition class. And we don't even break the Single Responsibility Principle...
And all though this is pretty cool, Multiple Inheritance still have a lot of other cool features also which are nice to have, especially when developing GUI libraries like Ra-Ajax
Anders Hejlsberg - WE REALLY NEED MULTIPLE INHERITANCE! ;)
Still, above there's "one less problem to deal with" for those of you missing the good old C days with Multiple Inheritance...
Have a nice day :)
Thomas