Composition Over Inheritance
There are two main ways an object can interact with another object.
It can have the other object as a property: this is called composition.
Or it can inherit the other object: this is called inheritance.
Composition over inheritance is a programming concept stating basically that composition is preferred to inheritance.
I will not talk about the polymorphism aspect of this to simplify the discussion.
The reason for this is that inheritance leads to rigidity while composition leads to flexibility.
One of the few useful things I learned at university was Object Oriented Programming.
I understood the concepts rather well and when I began working as a programmer I started using these concepts.
Back then I was using PHP and object oriented programming was optional.
But I was a big fan of OOP.
So naturally I wanted to use inheritance.
I was lucky enough to work alone on a lot on medium sized projects.
So any mistake or bad code I wrote turned against me.
It was easy to see what was maintainable and what was not.
There was no one else to blame, all the mistakes were mine to learn from.
All the clean code and good practices were also mine to understand and reuse.
I started using inheritance a lot.
I thought it was a good way to write code and one of the best ways to avoid code duplication.
And I was wrong.
After a month or two on the same project this became obvious.
That’s about the time when I would want to inherit more than one class.
Which is not possible in PHP.
Or Java, or C#.
And this is a good thing.
This was the first sign that inheritance was turning against me.
After a few more days, the second sign would appear:
I had children that needed some of the parent’s methods but not the others.
The solution was simple, right?
No, I’m not talking about some sort of partial inheritance, that violates the Liskov substitution.
The Liskov substitution principle says that children objects must be able to replace parents in an application.
If you ever saw in a method something like “throw exception, not implemented in this child class” you saw a violation of the Liskov substitution.
There are some complex reasons for why this is bad, but just the fact that it’s incredibly unexpected is enough for me.
A big part of clean code is to be predictable.
The correct solution was breaking the parent classes into multiple smaller classes, to make them more flexible.
Splitting inheritance with multiple levels is not something pleasant.
It also destroyed my system of abstraction of reality.
This was the third bad sign.
For example I started with one Dog parent class.
After I had to split it I ended up with three different classes:
FoodEeater, BallChaser and MansBestFriend.
This had almost nothing to do with the reality I was trying to abstract.
My new classes on the tree no longer belonged there, the inheritance chains became hard to manage and I was not sure where a class should fit.
I did this in two or three projects until I finally gave up and accepted that composition was superior to inheritance.
Inheritance is a great concept, in theory.
But in my experience and in the experience of many programmers it fails in practice because of rigidity.
This is why we have this programming principle: Composition over inheritance.
I will show you a simple case when composition should be used instead of inheritance.
I know this is a very obvious case and nobody would use inheritance here.
But it doesn’t affect the point I’m making.
In my experience:
If you use inheritance when you should have used composition there will be hell to pay in the medium term.
If you use composition when you could have used inheritance, nothing bad will happen.
I can’t think of an instance when I thought someone used composition when they should have used inheritance.
This is counter intuitive when abstracting the world into code, but it gets obvious when the project grows.
The bigger your inheritance chain will grow, the more “could have used inheritance” turns into “should have used composition”.
This is because of the rigidity of inheritance.
But let’s see what happens when we use inheritance and we should have used composition to give a simple clear example.
We start with a horn class that can horn.
The business team asks us for a car class.
All that this car can do is to horn.
So we make it a child of the horn class.
In this example its obvious why this is wrong.
But when not working with such clear concepts like car and horn, it’s more fuzzy and you can make mistakes like this.
After two more sprints, the business team asks us for a steering wheel and the car should be able to steer.
I got to this point a few times when using inheritance.
The answer is obvious.
We switch to composition.
It’s a lot more simple simple if our car has a horn and a steering wheel instead of trying to be a horn and a steering wheel.
This article is part of the “Composition over Inheritance” episode from my Clean Code course.
You can watch the Clean Code courses here:
– Watch Clean code with Java examples course on Udemy
– Watch Clean code with PHP examples course on Udemy
– Watch this Clean code with Java examples – Basics for free here AND get 2 FREE months of skillshare.com Premium