The distinction between normal associations, aggregation and composition may not initially seem too complicated, but delving deeper into the definitions the UML presents and the complexities of software systems can muddy the waters. The choice you make can easily confuse those reading your diagrams unless the basis of your selection is made clear. The definitions of the terms are often interpreted quite subjectively, and the effect of change on a system, or in the conceptual model of one, can make earlier interpretations ambiguous.
The following definitions are taken from the UML 1.1 documentation [UML].
A special form of association that specifies a whole-part relationship between the aggregate (whole) and a component part.
A form of aggregation with strong ownership and coincident lifetime as part of the whole. Parts with non-fixed multiplicity may be created after the composite itself, but once created they live and die with it (i.e., they share lifetimes). Such parts can also be explicitly removed before the death of the composite. Composition may be recursive.
The definitions above seem fairly technical and watertight. The grey areas begin to appear when you start using them in practice. You can then find that the multiple requirements on composite relationships preclude them from an awful lot of cases where they might initially seem appropriate. If you look up aggregation and composition in a dictionary, you will see why - in non-technical usage these words are often almost interchangeable.
Some 'common sense' examples of aggregations could perhaps include a team being an aggregate of its players, a village of its inhabitants, a company of its workforce or a society and its membership. (The example in my earlier article was a box of paperclips and its contents [Blundell].) These are all examples of whole-part, or 'has-a' , relationships, and could be modelled using aggregation.
Similarly, some common sense examples of compositions could be a person and their limbs, heart, brain, and so forth, a stadium and its pitch and seats, a wall and the bricks from which it is built, and so on. In each of these cases, the composite is composed of its parts. You could consider writing a class diagram for the composite showing the parts as attributes. The attribute notation denotes composition, and so this would seem to make sense.
On closer examination, however, many of the above examples could be categorised quite differently.
There are a few problems with at least one of the above examples of aggregation. As Martin Fowler states [Fowler], there is dispute at this level even amongst the gurus. A company and its workforce is either an aggregation or just a simple association, depending upon who you listen to. Is this truly a whole-part, or 'has-a,' relationship? I think that the latest preference of at least some of the UML authors [Booch], is to say that this would indeed be an aggregation, if in part because the company is at a higher organisational level than its employees. An aggregation relationship is suitable to document this, as it can be seen as one basis for a whole-part relationship.
Looking at another example, if a society is disbanded, its membership details may well become irrelevant and so be destroyed. However, this coincident lifetime is indicative of the stronger aggregation form of composition.
The problems only get worse for composition. The definition for composition is quite strict, and involves the following rules:
whole-part relationship (it is an aggregation)
strong (not shared) ownership of part
coincident lifetimes of whole and part
addition/removal of parts allowed for non-fixed multiplicity
The first rule is from the definition of an aggregation. A composition association is an aggregation, and so a composition must still represent a whole-part relationship.
The second rule concerns the ownership of the parts by the whole. What happens, for example, if two walls meet, and the bricks forming the bond at the join are shared between the two walls? Do we now have one longer wall, or do we have two walls with shared bricks? A wall is logically composed of its constituent bricks1, yet we apparently have shared ownership in the joined-wall case, and this precludes composition, according to the UML at least.
Coincident lifetimes is the third requirement, implying that the bricks be created when the wall is built and destroyed when the wall is destroyed, which is not necessarily the case for our wall example. Furthermore, with the advances in spare-part surgery, a heart or kidney cannot be considered to have a composition relationship with their original owner if they can be taken out of one body and placed in another - a clear case of separate lifetimes. Even though the body and heart are created together, they need not be destroyed together. As you can see, the context of the problem is beginning to influence the choice of association here. If we are not building a system affected by transplant issues, then we may be quite happy with a choice of composition. For other systems such a choice may not be appropriate. One day, brain transplants may become a reality, and so today's cerebral composition may be tomorrow's aggregation of axons!
When the multiplicity of the part can be variable, clients are able to construct parts separately and attach them to the whole after it is created. Similarly they are allowed to detach them prior to destruction if necessary, as long as the lifetimes are still effectively coincident. This clearly opens up some lifetime-management issues to ensure that newly-created parts are indeed attached to the appropriate 'whole,' and are also destroyed after being detached prior to destruction of the whole. They must not be allowed to be reattached to another object at a later date. Your wall bricks or stadium seats must be destroyed with the wall or stadium, and cannot be used again.
Some practitioners use convenient rules-of-thumb for deciding between simple unadorned associations and aggregations, and between aggregation and full-blown composition. This is something to be wary of when viewing UML diagrams.
Some feel that the additional information given by these symbols is insufficient to warrant the ambiguity and confusion, and the trouble making the decision. They use simple associations for pretty much all cases, or perhaps use aggregation when something has a very strong whole-part relationship, possibly with related lifetimes as well. Others prefer to use aggregation fairly willy-nilly, ignore the coincident lifetime issues of composition and just focus on the un-shared ownership at one time (so an object can be detached and reattached to a different whole, as long as it isn't owned by more than one whole at a time). This can fit in with the informal perception of composition as simply the whole comprising the parts - a temporal definition that encompasses the whole-part idea and arguably the single ownership issue, but which is more liberal with the ancestry and ultimate fate of the parts.
Some draw UML diagrams only fairly close to the implementation end of development, and use the simple rule of aggregation for pointers and composition for values (and maybe constant pointer relationships used instead of values merely for efficiency or other implementation reasons). This works quite well, because at the implementation stage you have to start getting precise, and programming languages often support the technical distinction between composition and aggregation quite well. With heavy use of smart-pointers, however, you do have to be clear whether you have composition of objects from the problem space, or just composition of the smart pointer objects that manage them.
The advantage of some of these rules is that they can make the initial decision easier (if not automatic) to make, and so require less thought. Less thought is a good thing if the problem lies with the UML definitions. It is definitely a bad thing, however, if the difficulty arises because of an incomplete understanding of the system at hand, of the stage of development, of the type of diagram you are drawing/modifying (conceptual, specification or implementation), or of the technical differences between the various types of association. In these latter cases, additional thought is definitely required to sort out what you are doing!
The main points of agonising over these issues are to ensure that your diagrams are unambiguous, and that they clearly express your intent to those reading them, possibly long after they are drawn (or long after you have moved on). Individual associations can be marked with a note to explain the semantics intended for that individual case. Otherwise, a note on a diagram, or set of diagrams (or even a policy for all the diagrams in a project) can explain the default rationale behind all association choices, especially if it is partially at odds with the UML default.
The coincident lifetime issue is often the most problematic aspect of association selection, and the final choice usually depends strongly on the context of the model and on the system under development. Designing a system for change, however, means that you have to design for uses of the system not considered in the original specification. This is especially true when designing components for reuse, when today's composition could technically be tomorrow's aggregation and next week's simple association.
By the time you read this, version 1.3 of the UML should be out. A number of things have changed so far since the original publication of version 1.1 back in September 1997. Amongst other changes, there are now additional and modified standard stereotypes and tagged values for extending the core UML set of artifacts, particularly for associations. I hope to discuss these changes in a forthcoming article.
[UML] UML Semantics version 1.1, available from Rational's web-site: www.rational.com/uml, September 1997.
Overload Journal #30 - Feb 1999 + Design of applications and programs
|Browse in :||
All > Topics > Design (179)
Any of these categories - All of these categories