Composition and Inheritance in OOP (JS)

Bashir
3 min readOct 30, 2020

--

There are multiple ways to structure your code and when making structural decisions it is always best to keep in mind the idea of flexibility and scalability. You need to build an application with the goal of flexibility in mind. Meaning, are you able to add features easily to your app, or do you have to restructure your code to add in new features? If you built your app with flexibility in mind then you won’t have an issue adding to or removing features from your app. In this article, I will explain the main design patterns in Object Orient Programming (composition and inheritance) and explain the pros and cons of each and which design pattern you should choose.

Inheritance

Inheritance is one of the main pillars of object-oriented programming. It is the idea that classes can inherit or derive functionality from other classes. For example, if you have five classes that share the same methods, you can simply move those methods to a different class and make all classes inherit from this parent class. It is easier to see inheritance in code as shown in the code snippet below:

We have two classes in the code above: Cat and Person. Note that both classes share the functions “walk” and “eat”. This is a duplicate code which goes against the DRY principle of programming. Thus, the “walk” and “eat” functions can be put into a separate class that we can call “Animal” and have the Person and Cat classes inherit from the Animal class.

Looking at the code above, the “walk” and “eat” functions are written only once and they can be used in both the Person class as well as the Cat class because both classes inherit from the Animal class. So far this is great! But a problem arises as we begin to add additional code and functionality to our code down the road. For example, imagine we want to add a class called “TalkingParrot” which has only one method called “talk”. There is really no good and efficient way to add it to our code without facing a few hurdles.

class TalkingParrot {
talk()
}

We could simply implement the talk method and in this case, we’ll have a duplicate code with what we have in our Person class. As an alternative, we can make our TalkingParrot class inherits from the Person class. This will work, but then we are faced with the banana in the jungle problem; We are trying to get the “talk” function but we are getting the “talk” function along with everything in the Person Class and its parent class. So inheritance can really get complicated with large applications and if you structure things around you can unknowingly break countless other classes. All this can be circumvented by using composition.

Composition

Now that you saw the problems associated with inheritance, let’s dive into a composition together and see how we can avoid those problems. Composition is combining functional programming with objects to make code that is very flexible. Our for inheritance above can be written in the following way:

As you can see in lines 28 and 29, our Cat can be instantiated and the functions “walk” and “talk” can be called. Our Cat function returns an object which is written in lines 22 to 25. Using ES6, we can also use Object.assign to create our object, but to do so we’ll have to create functions that create objects for us as shown below:

As you can see, using composition is more flexible than inheritance and should be the preferred way to build an application. Your code will be more flexible to allow for additional functionality. Of course, there are some cases where class-based inheritance is preferred. For example, initiating instance objects is a bit faster using classes than functional objects(but this may be negligible in small to medium-sized applications).

--

--