Composition In OOP

Composition is special type of Aggregation. It is a strong type of Aggregation. In this type of Aggregation the child object does not have their own life cycle. The child object’s life depends on the parent’s life cycle. Only the parent object has an independent life cycle. If we delete the parent object then the child object(s) will also be deleted. We can define the Composition as a “Part of” relationship.

It describes a class that references one or more objects of other classes in instance variables. This allows you to model a has-a association between objects.

For example, the company and company location, a single company has multiple locations. If we delete the company then all the company locations are automatically deleted. The company location does not have their independent life cycle, it depends on the company object’s life (parent object).

Composition over Inheritance

Both composition and inheritance promote code reuse through different approaches. So which one to choose? How to compare composition vs inheritance. Its a saying that in programming we should favor composition over inheritance. Let’s discuss some of the reasons that will help you in choosing composition vs inheritance.

Inheritance is tightly coupled whereas composition is loosely coupled. Let’s assume we have below classes with inheritance.

Java
package com.journaldev.java.examples;

public class ClassA { public void foo(){ } } 

class ClassB extends ClassA{ public void bar(){ } } 

For simplicity, we have both the superclass and subclass in a single package. But mostly they will be in the separate codebase. There could be many classes extending the superclass ClassA. A very common example of this situation is extending the Exception class. Now let’s say ClassA implementation is changed like below, a new method bar() is added.

Java
package com.journaldev.java.examples;
public class ClassA { public void foo(){ } public int bar(){ return 0; } } 

As soon as you start using new ClassA implementation, you will get compile time error in ClassB as The return type is incompatible with ClassA.bar(). The solution would be to change either the superclass or the subclass bar() method to make them compatible. If you would have used Composition over inheritance, you will never face this problem. A simple example of ClassB implementation using Composition can be as below.

Java
class ClassB{ ClassA classA = new ClassA();
public void bar(){ classA.foo(); classA.bar(); } }

Access Control in Composition

There is no access control in inheritance whereas access can be restricted in composition. We expose all the superclass methods to the other classes having access to subclass. So if a new method is introduced or there are security holes in the superclass, subclass becomes vulnerable. Since in composition we choose which methods to use, it’s more secure than inheritance. For example, we can provide ClassA foo() method exposure to other classes using below code in ClassB.

Java
class ClassB { ClassA classA = new ClassA();
public void foo(){ classA.foo(); } 
public void bar(){ } } 

This is one of the major advantage of composition over inheritance.

Composition provides flexibility in invocation of methods that is useful with multiple subclass scenario. For example, let’s say we have below inheritance scenario.

Java
abstract class Abs { abstract void foo(); }
public class ClassA extends Abs{ public void foo(){ } } class ClassB extends Abs{ public void foo(){ } } class Test { ClassA a = new ClassA(); ClassB b = new ClassB(); 
public void test(){ a.foo(); b.foo(); } } 

So what if there are more subclasses, will composition make our code ugly by having one instance for each subclass? No, we can rewrite the Test class like below.

Java
class Test { Abs obj = null; 
Test1(Abs o){ this.obj = o; }
 public void foo(){ this.obj.foo(); } } 

This will give you the flexibility to use any subclass based on the object used in the constructor.

One more benefit of composition over inheritance is testing scope. Unit testing is easy in composition because we know what all methods we are using from another class. We can mock it up for testing whereas in inheritance we depend heavily on superclass and don’t know what all methods of superclass will be used. So we will have to test all the methods of the superclass. This is extra work and we need to do it unnecessarily because of inheritance.

Composition Hides Internal Code Changes

Using composition and encapsulation not only enables you to create better APIs, but you can also use it to make your code easier to maintain and modify. As long as a class gets only used by your own code, you can easily change it and adapt any client code if necessary.

Benefits of Composition

Composition is commonly used in carefully designed software components. When we use this concept, we can:

Reuse existing code

The main reason to use composition is that it allows us to reuse code without modeling an is-a association as you do by using Inheritance, that allows stronger Encapsulation and makes your code easier to maintain.

The concept of composition is often used in the real world, and it should be the same in software development. A bike is not an engine; it has one. And a coffee machine has a grinder and a brewing unit, but it is none of them. The bike and the coffee machine integrate an engine, grinder and brewing unit via their external APIs to compose a higher level of abstraction and provide more significant value to their users.

We can do it in the same manner in software development when you design a class to keep a reference to an object and to use it in one or more of its methods.

Design a clean API

Composition enables us to design clean and easy-to-use APIs. When we compose a class, we can decide if the referenced classes become part of the API or if we want to hide them.

As we explained in our article about Encapsulation, Java supports different access modifiers. It’s a common best practice to use the private modifier for all attributes, including the ones that reference other objects, so that it can only be accessed within the same object. If we want to allow external access to an attribute, we need to implement a getter or setter method for it.

If we use no access modifiers for a class, it becomes package-private. This class can’t be accessed outside of its own package and is not part of the API. External clients of your software component are not aware of this class. They can only use it via a public class that uses the package-private class in a composition.

Also Read

Association in OOP

Leave a Reply

Your email address will not be published. Required fields are marked *