DEV Community

Hassam Ali
Hassam Ali

Posted on • Updated on

Composition vs Inheritance

I recently completed an online course and these are my takeaway from Composition and Inheritance.

Inheritance

With inheritance we can extend the functionality of an existing class by overriding its method in a Child class e.g

class Parent {
  function sayHi() {
    console.log("sayHi from Parent");
  }
}
class Child {
  function sayHi() {
    console.log("sayHi from the Child");
  }
}
Enter fullscreen mode Exit fullscreen mode

Inheritance is characterised by an "is-a" relationship between two classes e.g Apple is Fruit, Car is a Vehicle etc. Inheritance is suited for use cases where there is tight coupling between the classes which is rarely the case in the real world.

Lets say your are building a house and you need to model a window in code. So you might come up with following:

class Window {
  height: number;
  width: number;
  open: boolean;
  toggleOpen() {}
  area(){}
}
Enter fullscreen mode Exit fullscreen mode

The properties are self explanatory. Pay attention to the area method. It calculates the area.
Now in addition to window we also want to add a Wall. The code for the wall might look as follow.

class Wall {
  height: number;
  width: number;
  color: string;
  area() {}
}
Enter fullscreen mode Exit fullscreen mode

You see that they share some common properties so you use inheritance for code reuse. You come up with class named Rectangle which has common properties from the both of the classes.

class Rectangle {
  height: number;
  width: number;
  area() {}
}

class Wall extends Rectangle {
  color: string;
}

class Window extends Rectangle {
  open: boolean;
  toggleOpen() {}
}
Enter fullscreen mode Exit fullscreen mode

So according to this code Wall is rectangle and Window is also a rectangle, now let's suppose the we want to introduce new type of window called circle window.

Circle window can not extend from Rectangle window because it does not make sense. Now this is a type of Window so you might be tempted to inherit from the window class but window class itself inherits from Rectangle so although it can be extended but it will also inherit the methods from Rectangle class which does not make sense and it as it is derived from Rectangle.

You wanted a banana but what you got was a gorilla holding the banana -- Joe Armstrong

So an other way is be to create a new Circle class and extend from it. It might seem a nice idea initially but as the application grows we might encounter again a similar situation. I will show on later how we can resolve this via composition.

class Circle {
 radius: number;
 area(){}
}

class CircleWindow extends Circle {
  open: boolean;
  toggleOpen() {}
}
Enter fullscreen mode Exit fullscreen mode

Composition

For this I would quote the following text from GoF Design Patterns Book

Object composition is an alternative to class inheritance. Here, new functionality is obtained by assembling or composing objects to get more complex functionality. [...] Object composition is defined dynamically at run-time through objects acquiring references to other objects

To recap, composition is an alternative strategy to class Inheritance for code reuse. In composition a class will have reference to another class instance as its memeber variable. Lets see this with an example. I will change the example in the last section.

interface Shape {
 area(): number;
}

class Wall {
  color: string;
  area(){}
  dimensions: Shape;
}

class Window {
  open: boolean;
  toggleOpen(){}
  area(){}
  dimensions: Shape;
}
class Rectangle implements Shape {
  height;
  width;
  area(){}
}
class Circle implements Shape {
  radius;
  area(){}
}
Enter fullscreen mode Exit fullscreen mode

So in this example inside Wall and Window we have a member variable called dimensions, which is of type Shape. The interface Shape guarantees us that their will be always a method named area present. So now we both Window and Wall can accept any object for its memember variable dimensions as long it satisfies the interface Shape, in a way we have delegated the responsibility for calculating the area to the class Rectangle and Circle

Inheritance vs Composition

So this was a quick recap of inheritance vs composition. This is very difficult to explain topics but with time you develop instincts for this. Now lets take a look at Abstract class and Interface. These are features provided by programming languages to aid in inheritance and composition.

Abstract Class

Abstract classes are classes for which you create an instance of them. They maybe used to provide a default implementation in case the overriding classes does not provide one. In javacript you can create an abstract class by adding the keyword abstract infront of the class.

abstract class Destroyer {
  onDestroy() {
    db.close();
    analytics.send("Database Closed);
  }
}
class MyDestroyer extends Destroyer {
}
The class MyDestroyer gets the implemntation defined in class Destroyer.
Enter fullscreen mode Exit fullscreen mode

Interface

Interface are used to define set of properties that must exist on class. Interface only contains what a class implentating that interface should have it does not dictate what it should do. Interface are loosely coupled compared to Abstract classes and are usually favoured.

In next part of the article I will show an example of inheritance and how to convert it into composition along with use of abstract and interface. stay tuned!🙂

P.S: if you find any mistakes please let me know in comments. Design Patterns are difficult to understand and even harder to write about.

Discussion (1)

Collapse
arvindpdmn profile image
Arvind Padmanabhan

Nice quote by Armstrong. Those who are new to OOP, can see devopedia.org/object-oriented-prog...