Monday, October 1, 2018

Vestigial Inheritance

Favoring object-delegation over inheritance as a way of sharing traits between classes is a field-proven technique. So many people "invent" that technique while they are learning that it's hard to trace it to its true origin.

Certainly, the Gang of Four did a lot to popularize the notion.

Yet, there are little places where people still tend to trip and fall back into inheritance as a way of sharing commonalities.

The Template Method pattern is one such place. People almost always implement it this way...

Two classes inheriting from a third. The base class has a public method and two abstract, protected methods. The inheritors implement the protected methods.
Inheritance-based Template Method pattern

...but there isn't really a good reason to make the interface for the specialization be a protected part of the generalization. It's just a carryover from habits formed before design patterns thinking was as prevalent as it is, today. It's the coccyx of the software development industry; a vestigial holdover from a time when it served a now-extinct purpose.

There's another way. One with no downsides and an almost unassailable upside. You can use inheritance to categorize and composition to pull specialization into the generalization.

Four classes. One class, Generalization, has a public method called "SharedPart()" and associates with another class named "Specialization". There are two inheritors of Specialization, each of which implements its two abstract methods, Step1() and Step2()
Composition-based Template Method pattern
One could easily mistake this for a Strategy pattern, missing the fact that it's the driver for variation that sets the pattern, not the drawing. Even if you don't want to believe that, and prefer to think of the Strategy pattern as a selector for a category of drawings such as the one above, the point remains the same.

Either way, the benefits of the latter design far exceed those of the former design without any meaningful drawbacks. Here are a few of the most prominent benefits of a composition-based Template Method pattern:


  • You have multiple categories of specialization, which vary independently.
  • It's easier to test each specialization directly.

Again, if your views on design patterns make you think I drew a Strategy pattern, then the same advantages would hold, with different language describing it: You can have multiple "Strategy patterns" that vary independently of one another and each implementation of a "Strategy" is more easily and concisely tested.

I implore people those of you are considering refactoring to a classic, inheritance-based Template Method to ask yourself "What would it really cost me to take this all the way to favoring object-delegation over inheritance?"