The Startup
Published in

The Startup

Composition or Inheritance, Which One Do You Prefer?

Inheritance is a great principle in object-oriented programming where we can reuse code. But we have to be careful when using it because sometimes inheritance makes our code fragile.

We can always start building an application in javascript with simple objects and if we see that several objects share similar behavior then we can create a generic object with those features and use inheritance.

Inheritance is not the only solution for code reuse. We have another technique in javascript which is Composition.

Suppose we have an Animal object with one method eat

Animal
.eat()
.walk()

Next, we have another object Person which have all the behaviors like Animal object. So we can derive Person from Animal .

Animal
.eat()
.walk()

Person

Suppose tomorrow we introduce a new object in our application which is Fish . Theoretically, we can derive Fish from Animal , but in our implementation Animal can walk and Fish can’t. So our hierarchy is broken.

For one object we could not maintain our hierarchy so if tomorrow we introduce a lot of new objects with different behaviors then it will be really difficult to maintain the inheritance or the hierarchy.

Here we can use composition to solve our current problem. In composition, we compose a few objects together to create a new object. We will create different features or behaviors as an independent object.

const canEat = {
eat: function() {
console.log('Eating');
}
};const canWalk = {
walk: function() {
console.log('Walking');
}
};
const canSwim = {
swim: function() {
console.log('Swimming');
}
};
const canFly = {
fly: function() {
console.log('Flying');
}
};

Now we can use those above objects to compose new objects. So if we want a bird object then we create that by composing canEat and canFly. If we want a Person object then we can compose canEat and canWalk .

From ES6 we can use Object.assign to implement composition.

const bird = Object.assign({}, canEat, canFly);

Here object.assign will copy all the properties and methods from canEat and canFly in the {} object and we are assigning the final object in bird variable.

If we want to use a constructor function then the implementation will be like

function Bird() {
// Here only write properties and methods that are specific
// to bird object
}
Object.assign(Bird.prototype, canEat, canFly);const bird = new Bird();

Here we are attaching canEat and canFly with the prototype of Bird function because in all objects created from the Bird constructor function will have the same prototype object. So basically we will have a single reference of that prototype object in memory. We should always attach the generic properties and methods with prototype. In this way we can save a lot of memory in large application.

Now we can extract the logic of composition and write a new function to reuse it.

function mixin(target, ...sources) {
Object.assign(target, ...sources);
}
mixin(Bird.prototype, canEat, canWalk);

So inheritance or composition, what you will use in your application is totally up to you. But we should keep in mind that inheritance is not the only option. Sometimes composition can help us to reduce complexity if we have a complex relationship hierarchy between objects. In that case, we can create each of the unique behaviors as an independent object, and later we can compose those objects to reuse them.

--

--

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
Ashraful Islam

Ashraful Islam

54 Followers

Software Engineer | Javascript Developer | React | React Native | Angular | NodeJS