Wednesday, October 2, 2024

5 Reasons to Use Composition over Inheritance in Java and OOP - Example

Favor composition over inheritance is one of the popular object-oriented design principles, which helps to create flexible and maintainable code in Java and other object-oriented languages. Many times I have seen people suggesting use composition instead of inheritance, in fact, my favorite books like Head First Design Patterns also advocate this design principle. The Head First books have their own way of explaining, why composition is better than inheritance, and though it's long it's quite interesting and informative. It was the first chapter of this book, which helped me a lot in understanding this key OOP concept. 

In this Java and OOP tutorial, I have tried to summarize my experience around composition and inheritance in two main categories, first, the difference between composition and inheritance, and second, when to use Composition over inheritance in Java. 

I have already mentioned this design principle, in my list of 10 OOPS and SOLID design principles for Java programmers, here we will take a closer look.

Just to revise, composition and Inheritance are ways to reuse code to get additional functionality. In Inheritance, a new class, which wants to reuse code, inherits an existing class, known as a superclass. This new class is then known as the subclass.

Btw, In order to best understand design patterns, you need to work out some scenarios, examples, etc. It's best to get this kind of knowledge as part of your work but even if you don't get there, you can supplement them by joining these online Java design pattern courses and doing some object-oriented software design exercises. 




5 Reasons to Prefer Composition over Inheritance in Java

On composition, a class, which desires to use the functionality of an existing class, doesn't inherit, instead it holds a reference of that class in a member variable, that’s why the name composition. Inheritance and composition relationships are also referred as IS-A and HAS-A relationships.

Because of IS-A relationship, an instance of sub class can be passed to a method, which accepts instance of super class. This is a kind of Polymorphism, which is achieved using Inheritance.

A super class reference variable can refer to an instance of sub class. By using composition, you don’t get this behavior, but still it offers a lot more to tilde the balance in its side.


1) One reason of favoring Composition over Inheritance in Java is fact that Java doesn't support multiple inheritance. Since you can only extend one class in Java, but if you need multiple functionality like e.g. for reading and writing character data into file, you need Reader and Writer functionality and having them as private members make your job easy. 

That’s called composition. If you are following programming for interface than implementation principle, and using type of base class as member variable, you can use different Reader and Writer implementation at different situations. 

You won’t get this flexibility by using Inheritance, in case of extending a class, you only get facilities which are available at compile time.


2) Composition offers better test-ability of a class than Inheritance. If one class is composed of another class, you can easily create Mock Object representing composed class for sake of testing. Inheritance doesn't provide this luxury. In order to test derived class, you must need its super class. Since unit testing is one of the most important thing to consider during software development, especially in test driven development, composition wins over inheritance.


3) Many object-oriented design patterns mentioned by Gang of Four in there timeless classic Design Patterns: Elements of Reusable Object-Oriented Software, favors Composition over Inheritance.

Classical examples of this are a Strategy design pattern, where composition and delegation is used to change Context’s behavior, without touching context code. 

Since Context uses composition to hold strategy, instead of getting it via inheritance, it’s easy to provide a new Strategy implementation at run-time. 

Another good example of using composition over inheritance is the Decorator design pattern. In Decorator pattern, we don't extend any class to add additional functionality, instead, we keep an instance of the class we are decorating and delegates the original task to that class after doing the decoration. 

This is one of the biggest proof of choosing composition over inheritance, since these design patterns are well tried and tested in different scenarios and withstand test of time, keeping there head high.



4) Though both Composition and Inheritance allows you to reuse code, one of the disadvantage of Inheritance is that it breaks encapsulation. If sub class is depending on super class behavior for its operation, it suddenly becomes fragile. 

When behavior of super class changes, functionality in sub class may get broken, without any change on its part. 

One example of inheritance making code fragile is method add() and addAll() from HashSet. Suppose, If addAll() of HashSet is implemented by calling add() method and you write a sub class of HashSet, which encrypt the content before inserting into HashSet. 

Since there are only one method add(), which can insert object into HashSet you override these methods and called your encrypt() method by overriding add().

This automatically covers addAll() as well, because addAll() is implemented using add(), it looks very enticing.

If you look closely you will see that this implementation is fragile, because its relied on super class behavior. If base class wants to improve performance and implements addAll() without calling add() method, following example will break.

public class EncryptedHashSet extends HashSet{
    .....

    public boolean add(Object o) {
       return super.add(encrypt(o));
    }

}




If you have used Composition in favor of Inheritance you won't face this problem and your class would have been more robust, because you are not relying on super class behavior any more. 

Instead you are using super class method for addition part and you will benefit with any improvement in addAll() as shown in below example:

public class EncryptedHashSet implements Set{

    private HashSet container;

    public boolean add(Object o) {
       return container.add(encrypt(o));
    }

    public boolean addAll(Collection c) {
       return conatainer.add(encrypt(c));
    }

    .......
}

In short, don't use Inheritance just for the sake of code reuse, Composition allows more flexible and extensible mechanism to reuse code. 




5. Another reason for favoring Composition over inheritance is flexibility. If you use Composition you are flexible enough to replace the implementation of the Composed class with a better and improved version. One example is using the Comparator class which provides compare functionality. 

If your Container object contains a Comparator instead of extending a particular Comparator for comparing, its easier to change the way comparison is performed by setting different type of Comparator to composed instance, while in case of inheritance you can only have one comparison behavior on runtime, You can not change it runtime.


And, here is a nice visual diagram or cheat sheet you can refer to learn why Composition is better than Inheritance in most of the cases:

5 Reasons to Use Composition over Inheritance in Java and OOP - Example




That's all about why programmer should favor composition over inheritance in object oriented programming. While there are many more reasons to favor Composition over inheritance, which you will start discovering once you start using design patterns in Java. In nutshell favoring Composition results in more flexible and robust code than using Inheritance. 

Though there are certainly some cases where using Inheritance makes much sense like when a genuine parent-child relation exists, but most of the time it makes sense to favor composition over inheritance for code reuse. 

There is also an item of this topic in my other favorite book, Effective Java, which has also helped me to understand this concept better, you may want to look at that as well.

Make sure you don't forget this rule, if you don't to do this :)

Always favor composition over Inheritance in Java and OOP


Other Java Design Patterns tutorials you may like
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • How to design a Vending Machine in Java? (questions)
  • How to implement a Decorator design pattern in Java? (tutorial)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • 20 System Design Interview Questions (list)
  • How to use Factory method design pattern in Java? (tutorial)
  • When to use Command Design Pattern in Java (example)
  • 7 Best Courses to learn Design Pattern in Java (courses)
  • How to create thread-safe Singleton in Java (example)
  • Difference between Factory and Abstract Factory Pattern? (example)
  • 7 Best Books to learn the Design Pattern in Java? (books)
  • How to implement the Strategy Design Pattern in Java? (example)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • 10 OOP Design Principle Every Java developer should learn (solid principle)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)
  • 7 Books to learn System Design for Beginners (System design books)

Thanks a lot for reading this article so far. If you like my explanation of the Composition over Inheritance in object oriented programming and in Java and find this article worth your time then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you are an experienced Java programmer and want to learn Design patterns and looking for a free online training course to start with then you can also check out this Java Design Pattern and Architecture free course on Udemy. It's completely free and you just need a free Udemy account to join this course.

13 comments:

  1. Favor Composition because it adds functionality at runtime, while Inheritance adds functionality at compile time.

    ReplyDelete
  2. To have more clarity on Why composition should be favored over inheritance, Please read http://efectivejava.blogspot.in/2013/07/item-16-favor-composition-ovr.html

    ReplyDelete
  3. Excessive use of composition creates way more objects, which hurts locality and increases GC duration as GC duration is a direct function of the number of objects and reference locality. So care should be taken when choosing Composition as your "default" pattern.

    ReplyDelete
  4. Hi Javin,
    Ur every articles are very nice and descriptive.only one thing if u add some more examples then
    it would be more useful for everyone.
    Thanks,
    Biraja Prasad Nayak

    ReplyDelete
  5. this is a hack and leads to bad design. if hashset is a set then inheritance should be used. if hashset uses some common functions with other classes then composition should be used. performance issues should be solved in compiler/interpreter level.

    ReplyDelete
  6. Andrius DobrotinasJune 2, 2015 at 9:33 AM

    "one of the disadvantage of Inheritance is that it breaks encapsulation" - actually, it doesn't. It doesn't make private fields accessible to the inheriting class, only protected ones. And if the one who designed the class made some of the fields protected, they made it for a reason.

    ReplyDelete
    Replies
    1. I also think the same. Somehow I couldn't get much except first two points.

      Delete
  7. 4 is completely wrong and contrived. You should NEVER depend on the implementation of a class, only the interface. The code signature and the document are all you look at. You should never go look at the superclass code and say "well since it's implemented this way, I could do this and achieve the same thing." Of course things are going to break if you do that sort of stuff.

    ReplyDelete
  8. Whats the point of using an OO language if you consider that one of its main feature is bad design ?

    ReplyDelete
  9. Hello PomPom, sorry didn't get you, can you elaborate what do you mean?

    ReplyDelete
  10. "In Decorator pattern, we don't extend any class to add additional functionality"
    But you need the Decorator to extend the base class.

    This is from your linked example:
    // Decorator

    public abstract class Decorator extends Currency{

    public abstract String getDescription();

    }

    So I get that Decorator doesn't extend Rupee in that example, but you need inheritance nevertheless, right?

    ReplyDelete
  11. Hello Boris, Yes you need Inheritance, so that Decorator class can stand in place of actual class. They both have same type because both of them extend from same parent. But Decorator is a combination of Inheritance and Composition as it allows one decorator to be used in different context.

    ReplyDelete