Inheritance and Composition

Image for post
Image for post

We quite got used to inheritance. This pattern is so common you probably use it every single application. The idea behind this pattern is simple: you may extend some object (class, type — whatever is more comfortable in your favorite language) simply inherit methods and properties from “parent” object (class, type) without duplicating its code.

Let’s say we have class “Animal”. This guy has several properties describing him: age, skin color, maybe nickname if it is a pet. Also, it has few methods like “lay”, ”stay”, “run” etc.

(Pay attention, that we usually use nouns for properties and verbs for methods)

Image for post
Image for post

Also imagine we have several other guys: fox, rabbit, dog. All of them are animals, in terms that they can act as animals. They can run, stay and lay as an animal. So we can say that all of them inherit these methods from parent object: Animal

Image for post
Image for post

Moreover, each of child object/class may have their own methods, not inherited from parent object/class. Let’s say Dog can bark(not all animals can do that), Rabbit can leap (once again — not all animals can afford that) and so on and so far.

Image for post
Image for post

This is very common conception and we really got used to it. But there is a problem with it and I’ll try to illustrate it.

How do you think, can animals swim? Well, some of them definitely can! In our case evidently, a dog can do that. Foxes are also capable to do so even though it’s not their favorite thing. What about rabbits? Well, this adorable video proves they can as well!

So we can simply add this kind of behavior to parent animal class because ALL animals can swim:

Image for post
Image for post

But… This is not true… Not all animals can swim… Let’s say we have object “Camel”. This guy knows how to lay, how to stay but nothing about swim! Oh… Does it mean camel is not animal? No, it just means that he can not swim and nothing more.

Well, we can create some class AnimalThatCanSwim, inherit it from Animal and then let classes of animals that actually can swim inherit from AnimalThatCanSwim. Yep, that should do the trick:

Image for post
Image for post

Alright, that was close. For a second I thought we had a problem!

Ok, now we have a request for another object: Turtle. Well, this guy can swim so let’s add him to a company with Rabbit, Fox, Dog:

Image for post
Image for post

But… Turtles can’t run… Ohhh, we need to change our architecture but hopefully just a bit. We will create another class AnimalThatCanRun and inherit Rabbit, Fox, Dog, and Camel from it. Also, Rabbit, Fox, and Dog will inherit from AnimalThatCanSwim.

Image for post
Image for post

Now, that should work! But wait… Turtle still can run but it can not in real life… I actually need here multiple inheritances but in most languages, we have no such thing because of “diamond problem”… I need something like this:

Image for post
Image for post

Ok, that’s become too complicated. Let’s forget about the turtle for a while. I have another request actually. I need to implement Eagle… Ok, this guy can fly, so I’ll create object AnimalThatCanRunAndFly… But eagles cannot run! Oh, my!

Wait for a second, I know what to do with all this!

I will create Magic Animal — class that has every single possibility at once! In my child classes, I simply remove (override to empty) methods I don’t need!

Image for post
Image for post

I think we all agree that this is not a solution. Our Animal becomes a HUGE class and now contains every single option. This case is very hard to maintain.

The main problem here is that our thinking was wrong from the beginning. Instead of thinking “what object might to inherit from” we should concentrate our thoughts on “how our object need to behave?

If we think in that way we may realize, that Rabbit can lay, stay, run and swim. So basically we need some components that add some extension to our Rabbit so he becomes “runnable”, “swimmable”, “layble” etc:

Image for post
Image for post

Similarly for Fox and Dog. For Camel this idea should look like this:

Image for post
Image for post

For Turtle and Eagle:

Image for post
Image for post

This pattern is called Composition. In a bunch of situations, it gives you flexibility and reduces the complexity of the code.

In our case, you are able to add a lot of animals and that won’t ruin your architecture. For example, you may add a Duck, who can run, stay, lay, swim and fly (lucky!); or a Shark who can only swim. Also, you are able to add new behaviors that will extend your object (for instance you might create “can bite” behavior and add to Dog, Fox, and Shark.

Please pay attention, that we used an adjective for names of behaviors. This should highlight the idea that Composition helps you add “abilities” to each class/object.

All that said doesn’t mean inheritance is bad and also doesn’t mean Composition is a “silver bullet”. Every tool has its strengths and weaknesses. Please refer to this article for more information and “edge cases”.

Written by

Software Engineer with about 15 years of experience in front- and back-end web development, and I know how to cook this dish!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store