Understanding Class Aggregation and Composition

If you spend anytime reading up on design patterns (I recommend this book), you'll come across terms like class association, aggregation, and composition. I recently stumbled into these and realized I didn't quite understand what they meant, nor what they might look like in the real world.

Below is my understanding of the terms and what they might look like in the wild (in PHP of course). I hope this would be more of a conversation than a lecture, so if you have other thoughts, corrections, or anything to add, I'd love to hear them.

What is Association, Aggregation, Composition anyways?

These terms refer to how classes relate to each other -- how they are combined in a system to achieve a goal. Association refers to classes that are associated to each other. Associations can take many forms, like how Cars associate with Roads, how Cars can be associated with Doors, and how Cars can be associated with Colors.

Aggregation and Composition are two different types of associations -- they are a more specific way of describing a relationship between two classes. Let's take a look at what they entail, as well as a few examples of how it might actually look in code.

Aggregation

Aggregation is when a container class has many aggregate parts that are themselves wholly individual classes. The aggregate classes are not dependent on the container class for their existence. An example of this is a Car class that has four tires, each tire being an instantiation of the Tire class. Because they are aggregately associated, each Tire is not dependent on the Car. You could take one Tire and assign it to a different instantiation of Car.

Let's look at what this might look like in PHP:

class Tire {}

class Car
{
    public function __construct(Tire $t1, Tire $2, Tire $t3, Tire $t4)
    {
        $this->tire1 = $t1;
        $this->tire2 = $t2;
        $this->tire3 = $t3;
        $this->tire4 = $t4;
    }
}

$tire1 = new Tire();
$tire2 = new Tire();
$tire3 = new Tire();
$tire4 = new Tire();

$suv = new Car($tire1, $tire2, $tire3, $tire4);

Another distinction that aggregation relationships entail is that the aggregate classes are not necessarily destroyed along with the container class. You can see in the above example that if $suv, an instantiation of Car that contains 4 tires, was destroyed the tires still exist and could be reused in another instance of Car.

This is powerful stuff, and there are tons of ways this plays out to be really useful. In the above scenario, an instantiation of Car has access to each of it's Tires and their public methods. Perhaps a Car object needs to call $this->tire1->checkTirePressure() or some other method on the Tire class.

A Summary of Aggregation

  • A container class contains aggregate classes that are wholly independent and exist as their own entities outside of the class.
  • In aggregation, when a container class is destroyed it doesn't necessarily mean it's aggregate classes are destroyed.

Composition

If we take composition as it's name, it implies that a container class is composed of other classes. By this we mean that in this relationship, there is a class that makes up a significant part of it's container. A component class is not an independent entity, but an entity that exists solely inside of the container class. We usually say that the component class does not make sense apart of it's larger container.

Keeping with the car example, let's say that each Car contains an ignition lock cylinder. We'll just refer to it as a lock. The lock is a component of a car, and when a car is destroyed, so is the lock. A lock is dependent on a car and has no use outside of it. Here, we say that a car is composed of a lock.

Mapping this over to code, we would want a container class Car, to be composed of a component class Lock. The class Lock shouldn't exist outside of the class Car, because it's existence doesn't make any sense outside of the Car -- at least in this system.

Let's take a look at what this would look like in PHP:

class Lock {}

class Car
{
    public function __construct()
    {
        $this->lock = new Lock();
    }
}

$suv = new Car();

The difference here is that we are not assigning an outside entity to Car, but that car is creating and assigning a Lock entity to itself. We cannot access this instantiation of Lock outside of the Car class (unlike Tire). Also, when an instantiation of Car is destroyed, so too does it's instantiation of Lock get destroyed.

A Summary of Composition

  • A container class contains component classes that are wholly dependent and do not exist as their own entities outside of the class.
  • In composition, when a container class is destroyed it results in it's component classes being destroyed as well.

Taking a Look at the Differences

The difference in the two is subtle. There is a difference in the relationship a lock has to a car than a tire has to a car. Locks are generally tied to a specific car, are not transferred to different cars, and are destroyed when the car is destroyed. A tire can exists separate from the car and might find further use after the car is destroyed.

However, it's not always that cut and dry. We as developers get to decide how we want to set up our class relationships. The decision of whether Aggregation or Composition makes sense for a given relationship is put on us.

Perhaps you are working on a project for a junk yard that resells car parts. In that case, it might make more sense to model the Car/Lock association as aggregation because maybe ignition lock cylinders do get put in different cars. Or maybe you, like me, can't help but feel anxious buying used tires, and so it would make sense to model the Car/Tire relationship as composition.

The decision is ultimately up to you.

I'm ending this with a great example from the Wikipedia post on object composition:

"For example, a university owns various departments (e.g., chemistry), and each department has a number of professors. If the university closes, the departments will no longer exist, but the professors in those departments will continue to exist. Therefore, a University can be seen as a composition of departments, whereas departments have an aggregation of professors. In addition, a Professor could work in more than one department, but a department could not be part of more than one university."