L'associazione di aggregazione

L'associazione di aggregazione è una relazione debole tra due classi.
Essa è un tipo di associazione tutto-parte (o tutto-parti), in cui una classe (detta classe tutto o contenitore o aggregato) è composta, cioè contiene, una o più istanze di un'altra classe (detta classe parte o componente).

Il termine relazione debole sta ad indicare che gli oggetti della classe parte esistono in qualità di componenti dell'istanza della classe tutto ma possono esistere anche indipendentemente da essa e viceversa.

Se l'oggetto della classe tutto viene distrutto, le istanze della classe parte possono continuare ad esistere autonomamente, oppure in un'altra classe aggregato.
L'indipendenza delle vite degli oggetti delle classi tutto e parte rappresenta la principale differenza con l'associazione di composizione, precedentemente esaminata.

Anche questa associazione è nota come associazione HAS-A, in quanto gli oggetti della classe tutto hanno (contengono) gli oggetti della classe parte.

Nei diagrammi UML, l'aggregazione si rappresentata con una linea continua con un rombo vuoto dalla parte della classe tutto.

Associazione UML di aggregazione

L'associazione può essere unidirezionale, ossia solo la classe tutto dipende dalla classe parte. In tal caso è presente anche una freccia a punta aperta dal lato della classe parte.

Associazione UML di aggregazione unidirezionale

Se la dipendenza è, invece, bidirezionale, non sono presenti frecce, come raffigurato nell'immagine seguente.

Associazione UML di aggregazione bidirezionale

Come già visto nel caso della composizione, possiamo dedurre che, necessariamente, la classe tutto deve dipendere dalla classe parte, in quanto, per forza di cose, deve avere uno o più attributi con funzione di contenitore delle istanze della classe parte.
Viceversa, la classe parte potrebbe non sapere di essere un componente della classe tutto, nel senso che potrebbe non avere nessun attributo che fa riferimento alla classe tutto a cui appartiene.
Ne consegue che è proprio questa caratteristica a determinare il tipo unidirezionale o bidirezionale dell'associazione.

Vediamo qualche esempio concreto per comprendere meglio.
Consideriamo il diagramma UML seguente:

Esempio di associazione UML di aggregazione, auto e ruota

Da un punto di vista logico, il legame tra l'automobile e le ruote è un legame debole, in quanto l'automobile può continuare ad esistere anche senza ruote e, viceversa, le ruote possono essere prelevate ed utilizzate su un'altra automobile.

Tale conclusione conduce, questa volta, l'analista a produrre il diagramma raffigurato.
Inoltre, l'analista potrebbe decidere che l'automobile sia a conoscenza dell'esistenza delle ruote (vedi attributo di tipo Ruota[*], ossia array di Ruota), ma non viceversa (la classe Ruota non presenta nessun attributo, o parametro di input/output di metodi di tipo Automobile).
Questo comporterebbe l'unidirezionalità dell'associazione, rappresentata nella figura.

Da un punto di vista tecnico, a differenza della composizione, il programmatore che implementerà il modello sarà libero di creare le istanze di Ruota internamente alla classe Automobile (nel costruttore o in altro metodo), oppure riceverle attraverso metodi setter o altri metodi specifici. Inoltre sarà libero di restituirle come parametro di output di metodi pubblici (es. getter).

Se, invece, il progettista avesse voluto che anche la classe Ruota fosse stata a conoscenza dell'automobile di appartenenza, allora l'associazione sarebbe stata bidirezionale, con le integrazioni illustrate di seguito.

Esempio di associazione UML di aggregazione, auto e ruote bidirezionale

Si noti la presenza dell'attributo e del parametro del costruttore, di tipo Automobile nella classe Ruota. In presenza di tale scelta del progettista, l'associazione deve, per forza di cose, essere bidirezionale, come evidenziato dall'assenza di frecce nella linea che unisce le due classi.