We've all heard the mantra
"Prefer Composition Over Inheritance"
But what exactly is the problem with inheritance? We'll its a difficult tool to use appropriately, so many times I've seen developers code themselves into a corner by creating a complicated inheritance hierarchy that becomes a nightmare to maintain and leads to very rigid fragile code.
The cause of all this I believe is the way we determine when inheritance is the correct choice.
The Problem with "IS A"
A general rule often applied is if the relationship between two classes can be described as IS A then inheritance is appropriate. The problem is that there needs to be no caveats to that description, it should apply always with no if's or but's.
Let us take an example of a square and rectangle class.
public class Square extends Rectangle
On the face of it this seems fine, a square is a rectangle.
But this will very quickly violate the Liskov Substitution Principle, imagine I decide to write some code that re-sizes rectangles, how is this code going to react when it increases the width of the rectangle and the height magically increases as well. As far is this piece of code is concerned a square is NOT a rectangle.
The IS A relationship must always be true with no deviations otherwise inheritance will eventually cause you problems.
Lines of Communication
The other big smell with regard to inheritance is when the super-class and the sub-class interact by calling methods on each other.
A super-class should function in its own right and not reach up into a sub-class for functionality, conversely a sub-class should not treat its super-class like a member variable.
In these instances the relationship is best described by USES A or HAS A, composition is always the right choice when this happens. It will ensure the code is flexible and easier to test by making it SOLID.
We've already seen how badly implemented inheritance can break the Liskov Substitution Principle (LSP), it will very often also break the Dependency Inversion Principle (DIP) since by definition high level modules (the sub-class) will rely on low-level modules (the super-class) neither of which is being accessed via an abstraction.
There is no tighter coupling then between a sub-class and its super-class so to introduce such a dependency you have to be sure its the right thing to do.This is not to say there aren't valid uses for inheritance but there are many fewer of these then you may think so always ask yourself "Is this definitely always one of those?"
No comments:
Post a Comment