Aggregation and Composition with Java
Let’s understand the how relationships work
Relationships between classes are very important in object-oriented programming paradigm. The classes and OOP are built to model real-world entities. And the relationships between classes has been introduced to model the connections between real-world entities, which are mapped to classes.
Classes without any relations between them are impractical in OOP. Because usually in the real world, almost every entity is somehow connected to another entity.
If we take relationships, we can see a set of very common relationship types which are found in the real world also.
- One to many — 1 entity is connected with more than 1 instance of another entity. Ex: Company(1) has employees(N)
- Many to many — more than 1 instance of an entity are connected with more than 1 instance of another entity. Ex: Many courses(N) can be taught by many Lecturers(M) also.
- Many to one — 1 entity is connected with more than 1 instance of another entity. Ex: Multiple Lecturers(N) can be assigned to work in 1 department(1).
- One to one — 1 entity is connected with only 1 entity. Ex: 1 Person(1) has only 1 Mother(1).
Let’s see what association means…
Forms of Relationships
There are 2️⃣ main forms of relationships in OOP paradigm.
- IS-A (Inheritance)
- HAS-A (Association)
IS-A Relationship
This is exactly Inheritance in OOP. That is parent — child communication. Let’s take some examples…
- Car IS A Vehicle
- Cat IS AN Animal
- Manager IS AN Employee
All these examples denote that sub type is in the form of super type creating is-a relationship.
HAS-A Relationship
This means the Inter Connection between 2 entities/objects in real world which simply called Association. Let’s take some examples…
- Hotel HAS Rooms
- School HAS Departments
- Employee HAS Address
This represents the ownership of an entity in another. One entity belongs to another…
There are 2️⃣ forms of Association that are possible in Java:
a) Aggregation — loose coupling, weak
b) Composition — tight coupling, strong
Let’s get into the crucial part in the article! 💪
Aggregation
In aggregation, entities are loosely coupled together. The each entity can survive its own, independently. There is only a dependency on the other. If the Container is destroyed, Component should be able to survive.
Let’s take an example…
Imagine we have Employee class having id, name and address. Here address in having street and city. Basically we have 2 classes. Employee and Address. According to aggregation definition, the Address should be independent in which the Employee is composed of an address. Address should be able to survive its own.
Look at the below snippet. Employee is accepting an address object via the constructor which means we need an address to create an Employee. Employee HAS an Address! 😎
public class AggregateEmployee {
private final int id;
private final String name;
private final Address address;
public AggregateEmployee(int id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "AggregateEmployee{" +
"id=" + id +
", name='" + name + '\'' +
", address=" + address +
'}';
}
}
Client code:
public class AggregationTest { public static void main(String[] args) {
Address address = new Address("street 1", "city 1");
AggregateEmployee e = new AggregateEmployee(1, "Tim", address);
System.out.println(e);
}}
But see here..The address object can live in the code, without any help of Employee! Outer world can create Address objects without any interference. Am I right??? Yeah..It’s totally independent. So, we have implemented Aggregation using Java now!!!
Let’s move onto Composition.
Composition
In contrast to aggregation in composition, entities are tightly coupled together. The dependent entity cannot survive its own. If the Container is destroyed, Component is also destroyed and no longer exists.
Let’s take the same example…Employee and Address…
Now, Employee is accepting both parameters — city and street which are needed to create an address. Instead of injecting Address object via constructor, now employee is creating an Address object runtime inside the constructor. And this Employee has an private inner class of Address!
public class CompositeEmployee {
private final int id;
private final String name;
private final Address address;
public CompositeEmployee(int id, String name, String street, String city) {
this.id = id;
this.name = name;
this.address = new Address(street, city);
}
@Override
public String toString() {
return "CompositeEmployee{" +
"id=" + id +
", name='" + name + '\'' +
", address=" + address +
'}';
}
private static class Address {
private final String street;
private final String city;
public Address(String street, String city) {
this.street = street;
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"street='" + street + '\'' +
", city='" + city + '\'' +
'}';
}
}
}
Client code:
public static void main(String[] args) {
CompositeEmployee e = new CompositeEmployee(1, "John", "street 1", "city 1");
System.out.println(e);
}
Did you notice the change here? Can the Address survive if the Employee is destroyed? If the Employee class is deleted? No!!! Right? Since it’s a private inner class, it’s not accessible to the outer world also! Then clients cannot create independent objects of Address! It implies that Address is tightly coupled with the Employee…So, we have implemented Composition also using Java now!!!
This is pretty straight forward…This is how to implement the concepts using java. Keep in mind, this will be a common interview question also! So, try to understand with a real world scenario. It will make our lives easier! ❤️ 🙉