Composition over Inheritence – Still Confused?

But no one ever mentioned composition!

I vividly remember the time when I first read about OOPs (mostly because of the funny acronym). I was in school. I recall memorizing the concepts – Polymorphism, Inheritance, Encapsulation, Abstraction… writing them down on a notepad, carrying it around and trying very hard to not get confused between polymorphism and overloading(they are same, right?).

I also remember preparing for job interviews(I mean it has not been that long), interviewer ready to ask OOPs key concepts and me just spitting out the definitions, not really knowing what they really mean.

I finally deciphered these concepts while working as a professional programmer. I was happy, feeling smart. These concepts were not just theory (Unlike most of the stuff taught in school and college). I could actually use them.

Then the day came. I saw it. Written somewhere. The devastating words – ‘Inheritance is Evil’! I was like “why would someone say that?!” “This is just not right”. I have been trying to learn the concept of inheritance since the day I started coding for the first time.

But it was everywhere. ‘Favor composition over inheritance’ is a design principle! Why has no one ever mentioned composition before?! I could not understand what composition is and why inheritance is suddenly evil to save my life.

Anyways, it took me time to get over it and finally understand what people were talking about. Although I do not agree with the statement that inheritance is evil, I do understand the idea behind favoring composition over inheritance.

The concept of inheritance is simple – It lets you create the family of objects. Speaking of which, let’s take the example of my family to explain the concept of composition (sounds like a fun idea).

If you were to represent your family members in the OO program, the first thing you would do is define an interface to represent your family. Each family member will have a set of behaviors. As considering all the behaviors will be an impossible task, I will just take one example – how my family members walk in a shopping center (again, sounds like a fun idea).

This is how the interface will look like

public interface MyFamilyMember {
      public void walkInShoppingCenter();
}

My mom and sisters stop at every single shop when they are in a shopping mall even if they don’t need to buy anything. My dad, on the other hand, does not stop at any shop at all and my brothers will just run to the game center at the moment we enter the mall.

This is how class representation of each family member will look

public class MyDad implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Just walking without stopping at any shop");
      }
}

public class MyMom implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Walking while stopping at every shop");
      }
}

public class MyElderSister implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Walking while stopping at every shop");
      }
}

public class MyYoungerSister implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Walking while stopping at every shop");
      }
}

public class MyBrotherNumberOne implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Running straight to game center");
      }
}

public class MyBrotherNumberTwo implements MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Running straight to game center");
      }
}

And this is how I would ask my brother to walk

MyFamilyMember myBrotherNumberTwo = new MyBrotherNumberTwo();
myBrotherNumberTwo.walkInShoppingCenter();

//The output will be - Running straight to game center

What is the first thing that you notice here?

What was that? that I have a big family?

Not that! What else do you notice?

That’s right. Duplication.

MyMom, MyElderSister, and  MyYoungerSister have the exact same implementation of walkInShoppingCenter behavior. Both of my brothers have the same implementation too.

If you are anything like me, you must be thinking “Don’t be ridiculous, use an abstract class instead of interface”. Yes, I can easily avoid duplication by using an abstract class instead of the interface to define the MyFamilyMember interface and provide default definition to walkInShoppingCenter behavior.

(Note: Don’t get confused by the use of the word ‘interface’ here. ‘Interface’ is a concept. And both ‘abstract class’ and ‘interface’ constructs of java or c# are ways to implement ‘interface’ concept.)

Let’s try abstract class,

public abstract class MyFamilyMember {
      public void walkInShoppingCenter(){
            system.out.print("Walking while stopping at every shop");
      }
}

public class MyDad extends MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Just walking without stoping at any shop");
      }
}

public class MyMom extends MyFamilyMember{
}

public class MyElderSister extends MyFamilyMember{
}

public class MyYoungerSister extends MyFamilyMember{
}

public class MyBrotherNumberOne extends MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Running straight to game center");
      }
}

public class MyBrotherNumberTwo extends MyFamilyMember{
      public void walkInShoppingCenter(){
            system.out.print("Running straight to game center");
      }
}

Even though ‘Walking while stopping at every shop’ as default behavior doesn’t seem right(or does it?), it reduces redundancy to the greater extent. Yet using abstract class did not solve the problem completely either. My brothers are still providing the exact same implementation of the behavior.

This is where inheritance doesn’t solve the problem further. And situations like these make people dislike the inheritance.

Anyhow, we still have to solve the problem. So let’s try a different approach. Instead of considering every style of walking as ‘the behavior’, consider the walking as ‘family of behaviors’ with each behavior performing a particular style of walking.

This is how the interface for the family of walk behaviors can be defined :

public interface WalkInShoppingCenterBehavoir{
      public void perform();
}

Now we can define different styles of walking using this interface

public WalkWithoutStopping implements WalkInShoppingCenterBehavoir{
      public void perform(){
            system.out.print("Just walking without stoping at any shop");
      }
}

public WalkWhileStoppingAtEveryShop implements WalkInShoppingCenterBehavoir{
      public void perform(){
            system.out.print("Walking while stopping at every shop");
      }
}

public RunToGameCenter implements WalkInShoppingCenterBehavoir{
      public void perform(){
            system.out.print("Running straight to game center");
      }
}

Let’s assign these behaviors to respective family member

public abstract class MyFamilyMember {
      WalkInShoppingCenterBehavoir walkInShoppingCenterBehavoir;
      public MyFamilyMember(WalkInShoppingCenterBehavoir walkInShoppingCenterBehavoir)
      {
            this.walkInShoppingCenterBehavoir = walkInShoppingCenterBehavoir;
      }
      public void walkInShoppingCenter(){
            walkInShoppingCenterBehavoir.perform();
      }
}

public class MyDad extends MyFamilyMember{
      public void MyDad(){
            super(new WalkWithoutStopping());
      }
}

public class MyMom extends MyFamilyMember{
      public void MyMom(){
            super(new WalkWhileStoppingAtEveryShop());
      }
}

public class MyElderSister extends MyFamilyMember{
      public void MyElderSister(){
            super(new WalkWhileStoppingAtEveryShop());
      }
}

public class MyYoungerSister extends MyFamilyMember{
      public void MyYoungerSister(){
            super(new WalkWhileStoppingAtEveryShop());
      }
}

public class MyBrotherNumberOne extends MyFamilyMember{
      public void MyBrotherNumberOne(){
           super(new RunToGameCenter());
      }
}

public class MyBrotherNumberTwo extends MyFamilyMember{
      public void MyBrotherNumberTwo(){
            super(new RunToGameCenter());
      }
}

I will break down what got changed in this approach

  1. MyFamilyMember interface has a parameterized constructor which is taking the WalkInShoppingCenterBehavoir as a parameter.
  2. Only one implementation is needed for walkInShoppingCenter() which is provided by MyFamilyMember abstract class itself.
  3. Each implementation of MyFamilyMember interface now provides the desired WalkInShoppingCenterBehavoir.

In this approach, duplication is removed completely and the code to make my brother walk does not change at all. Also, if in future one of my brothers decides to walk in the mall while stopping at every shop instead of running to the game center, it will be just the matter of changing the injected behavior without changing the implementation of the behavior itself.

public class MyBrotherNumberOne extends MyFamilyMember{ 
      public void MyBrotherNumberOne(){ 
            super(new WalkWhileStoppingAtEveryShop()); 
      } 
}

It also gives me the means to reuse the existing code if I were to create more family members. For example, one of my sisters is married now and my brother in law is a part of the family too.  Like my dad, he also walks without stopping at any shops in the mall. This is how class representation for him will look like

public class MyBrotherInLaw extends MyFamilyMember{ 
      public void MyBrotherInLaw(){ 
            super(new WalkWithoutStopping()); 
      } 
}

I don’t have to implement any new behavior.

This is what we did here. We have combined WalkInShoppingCenterBehavoir and MyFamilyMember to create family members walking in different style with the flexibility of changing behavior without changing the actual implementation of behaviors.

This, my friend, is called Composition. To define, combining two or more objects to achieve more complex objects is called composition. Composition produces object implementation with the flexibility to change underlying behaviors easily.

And this is why they say ‘Favor composition over inheritance’.

We are still using inheritance here but it is only being used to define all the objects under the same type (this is how I will know that it is my family member) but the behavior is not being inherited. Instead, the behavior is being injected.

I know the example I took here is a bit silly (okay, okayyy extremely silly) but this principle is incredibly useful when it comes to designing systems which deal with a lot of different types of objects whose behavior varies at runtime.

I learned the true importance of this principle while working on an enterprise service bus (ESB) style application which processed files coming from various sources. Every file was supposed to go through few processing steps but the implementation of the steps vary depending on the metadata on the file. Injecting those steps as behaviors, like in this example, produced neat implementation with the flexibility to incorporate new types of files easily in future.

In spite of the fact that inheritance comes as an obvious solution to us most of the time (partly because we have heard about it since we started coding), more often than not favoring composition will make your application more resilient to the future changes in requirements.

P.S. – I couldn’t post on Thursday due to the sudden increase in workload. I will be posting on every Saturday or Sunday (still have to figure out which one works) from now on as it seems more doable.

Leave a comment