Mon 5 Dec 2011
Inheritance vs Composition
I recently wrote a blog post about the Strategy Pattern and have been thinking more about how it’s a neat pattern for composition. That line of thought took the voices in my head to discussing ways we construct classes, with various forms of code reuse and interface definitions, by applying design patterns.
That’s a large topic so let’s narrow focus and talk about two options for code reuse: inheritance vs composition.
Object-oriented systems are characterized, in part, by inheritance. We use polymorphism and dynamic binding as tools for switching about objects and allowing the system to choose the best method implementation for a given call.
This flexibility makes code easy to change. Method calls don’t care about which method they call providing the signature/type look correct — you can dynamically swap out the method implementation behind the scenes without syntactically breaking legacy code. Inheritance makes code changes easy when you’re creating a new subclass.
We’re going to need an example (from our code base, heavily modified for illustration):
public class Artifact {
protected void initializeDefaultValues(Project project) {
}
public boolean isScheduled() {
return Objects.firstNonNullValue(transientIsScheduled, isScheduled);
}
}
public class StoryCard extends Artifact {
@Override
protected void initializeDefaultValues(Project project) {
state = getInitialCreationStateReadOnly();
}
}
Artifact artifact = new StoryCard(); // polymorphism
artifact.initializeDefaultValues(project); // dynamic binding
StoryCard card = new StoryCard();
if (card.isScheduled()) {
…
}
Superclass–subclass relationships are fragile. If we decide to change the signature of Artifact’s initializeDefaultValues method this forces us to change StoryCard to match the new signature (along with the seven other subclasses which override this method). This was part of the motivation for introducing the @Override annotation.
Inheritance is said to provide weak encapsulation. Look back at if(card.isScheduled()). The card object was declared as type StoryCard but since StoryCard extends Artifact it inherits the isScheduled method. Here be danger: changes to isScheduled() in Artifact must be aware that subclasses, such as StoryCard, are relying on it: subclasses know about the method and can call it. Yes, the method is encapsulated but with a weak abstraction.
So inheritance can make it difficult to change the interface of a superclass. As an alternative we can use composition. Here’s a trimmed down version of our example to illustrate:
public class Artifact {
public boolean isScheduled() {
return Objects.firstNonNullValue(transientIsScheduled, isScheduled);
}
}
public class StoryCard {
private Artifact artifact = new Artifact();
@Override
public boolean isScheduled() {
return artifact.isScheduled();
}
}
Building StoryCard by composing in Artifact brings the isScheduled method up-front; it is implemented in the back-end by Artifact. By having StoryCard explicitly call isScheduled in Artifact we’ve more strongly encapsulated the method. This forwarding or delegation means we can alter isScheduled in Artifact without breaking any code calling isScheduled on a StoryCard typed object.
Another advantage of composition is that you may delay the creation of back-end objects until you need them. This can be more efficient if there is a lot of overhead in constructing those back-end objects. And since you’re hiding these back-end objects you can dynamically switch out that back-end object at run time — something you cannot do with inheritance. On the flip-side, when using composition the addition of new subclasses requires more effort.
So how do you choose? Traditionally we say inheritance follows the is-a pattern. A StoryCard is-a Artifact so we use inheritance. I would take this a step further and say that the is-a relationship must be true for the entire lifecycle of an object. If that’s not always true then maybe composition is more appropriate.
TL;DR; don’t automatically choose inheritance for code reuse and polymorphism — there must be an full-lifecycle is-a relationship between objects otherwise composition with interfaces may be a better alternative.

That’s an excellent article.
I would suggest to note the fact that both polymorphism and dynamic binding can also(and sometimes are better off) be accomplished using an interface.
In my opinion the only reason to prefer inheritance over composition is:
a. When the base class has some concrete logic that might need some injection points.
b. When you have to (when you “inherit” a design).
I’m glad that you agree with my post.
If I understand what you mean by “injection points” then you’re right. Most of the time. I avoid the use of injections points + base class implementation to complete the implementation of that base class. To fully understand this kind of code you need to (1) read the base class code, (2) jump to the subclass to read its implementation, and (3) go back to the base class to fully figure out what it all does.
This pattern is an example of the fragility I wrote about above. Changes to method signatures in the base class force updates to every single subclass. Plus the resulting code is a PITA to understand — which makes Ryan an angry fellow