Aggregation and composition

Hello!

I always thought that aggregation is a synonym for composition, but I came across a blog on the Internet where shows the differences between composition and aggregation .

It blew my mind. Please explain the pros/cons of both using small examples. How does this affect extensibility, testability, etc.

Author: Arhadthedev, 2016-11-28

1 answers

There are several types of interaction of objects, united under the general concept of " Has-A Relationship "or"Part Of Relationship". This relation means that one object is an integral part of another object.

There are two subspecies of this relationship: if one object creates another object and the lifetime of the" part "depends on the lifetime of the whole, then this is called "composition", if one object gets a reference (pointer) to another object during construction, then this is already an aggregation.

Let's look at an example from .NET Framework to see what limitations/implications these relationships carry: StringWriter + StringBuilder.

The StringWriter class is a specialized version of the TextWriter class, which is actively used for serialization and for getting a text representation of objects.

Specifically, StringWriter creates a string representation of an object or graph of objects and relies on an instance of StringBuilder in its work. I.e., we can say that 'StringWriter HAS A StringBuilder' or 'StringBuilder is part of StringWriter'. Now let's see how to decide whether StringWriter should get an instance of StringBuilder - a from outside or create it?

On the one hand, as a client of the StringWriter class, we often don't care what exactly is used inside this class to get a string representation. This means that from the point of view of ease of use, it is better that StringWriter creates an instance of StringBuilder-a independently.

But, on the other hand on the other hand, a particular object StringWriter-a can only be responsible for getting part of the string representation, and the other part of the string can be calculated in a different way. From this point of view, it is better that StringWriter accepts the StringBuilder - a instance in the constructor. The same is true for high-load systems where it is reasonable to use a pool of objects.

Since StringWriter is a library class that must support both scenarios, it has overloaded versions of the constructor: one of them is creates StringBuilder inside, and the other one accepts it outside.

In other words, the choice between composition and aggregation is based on maintaining a balance between different design requirements:

Composition: Object A controls the lifetime of object B

Pros:

  • The composition allows you to hide the relationship of the use of objects from the eyes of the client.

  • Makes the API for using the class simpler and allows you to switch from using one class, to another (for example, StringWriter could change the implementation and start using a different type, for example CustomStringBuilder).

Cons:

  • The relationship is quite rigid, because one object must be able to create another: it must know the specific type and have access to the creation function. Composition does not allow the use of interfaces (without involving factories) and requires a class to have access to the constructor of another class: imagine that the StringBuilder - a constructor is internal or it is an interface IStringBuilder and only the client code knows which instance should be used here and now.

Aggregation: Object A gets a reference to object B

Pros:

  • Weaker connectivity between the object and its client. Now we can use interfaces and one object doesn't need to know exactly how to create another object.

  • More flexibility. Follows from first item

Cons:

  • Exposing the implementation details to the outside. Since the client of the class must provide a dependency at the time of object creation (pass an instance of StringBuilder - a at the time of creation of StringWriter - a, the fact of this relationship becomes known to the client.

  • The first point implies an increase in complexity in the work of clients, as well as a greater "rigidity" of the solution in the long term. Now the author of the TextWriter class is no longer it can make a decision on its own and move from StringBuilder - a to something else. Yes, you can "add another layer of abstraction" and highlight the interface IStringBuilder, but it will be impossible to break this relationship completely without breaking all existing clients.

In conclusion: design is a search for a compromise between various factors. Composition is simpler from the point of view of class clients, but imposes certain restrictions: the " whole "must be able to create a "composite part". Aggregation is more flexible, but it imposes other restrictions: now the "whole" does not hide the existence of the" component part", and therefore will not be able to replace it with another" component part " in the future.

P.S. If you really want to use an example from the real world, then you can use it to explain composition and aggregation ... a screwdriver. If the screwdriver is one piece, i.e. the handle and the nozzle are tightly connected to each other, then we have the relation of the composition. If the nozzle is removable and can exist without a handle or if the handle is used with another handle, then we have the aggregation relation.

 42
Author: Sergey Teplyakov, 2016-11-29 02:58:02