Composition, agrégation et association en Java

Introduction

Les objets ont des relations entre eux, aussi bien dans la vie réelle qu’en programmation. Il est parfois difficile de comprendre ou de mettre en œuvre ces relations.

Dans ce tutoriel, nous nous concentrerons sur la prise en charge par Java de trois types de relations parfois facilement mélangées : la composition, l’agrégation et l’association.

Composition

La composition est une relation de type  » appartient à « . Elle signifie que l’un des objets est une structure logiquement plus grande, qui contient l’autre objet. En d’autres termes, il fait partie ou est membre de l’autre objet.

Alternativement, nous l’appelons souvent une relation  » has-a  » (par opposition à une relation  » is-a « , qui est l’héritage).

Par exemple, une pièce appartient à un bâtiment, ou en d’autres termes, un bâtiment a une pièce. Donc, fondamentalement, que nous l’appelions « appartient à » ou « a » n’est qu’une question de point de vue.

La composition est un type fort de relation « a » car l’objet contenant la possède. Par conséquent, les cycles de vie des objets sont liés. Cela signifie que si nous détruisons l’objet propriétaire, ses membres seront également détruits avec lui. Par exemple, la pièce est détruite avec le bâtiment dans notre exemple précédent.

Notez que cela ne signifie pas, que l’objet contenant ne peut pas exister sans aucune de ses parties. Par exemple, nous pouvons abattre tous les murs à l’intérieur d’un bâtiment, donc détruire les pièces. Mais le bâtiment existera toujours.

En termes de cardinalité, un objet contenant peut avoir autant de parties que nous le souhaitons. Cependant, toutes les parties doivent avoir exactement un contenant.

2.1. UML

En UML, nous indiquons la composition avec le symbole suivant:

Notez, que le losange est à l’objet contenant et est la base de la ligne, pas une tête de flèche. Par souci de clarté, nous dessinons souvent aussi la tête de flèche :

Donc, nous pouvons utiliser cette construction UML pour notre exemple de Building-Room :

2.2. Code source

En Java, nous pouvons modéliser cela avec une classe interne non statique :

class Building { class Room {} }

Alternativement, nous pouvons également déclarer cette classe dans un corps de méthode. Peu importe qu’il s’agisse d’une classe nommée, d’une classe anonyme ou d’une lambda :

class Building { Room createAnonymousRoom() { return new Room() { @Override void doInRoom() {} }; } Room createInlineRoom() { class InlineRoom implements Room { @Override void doInRoom() {} } return new InlineRoom(); } Room createLambdaRoom() { return () -> {}; } interface Room { void doInRoom(); }}

Notez, qu’il est essentiel, que notre classe interne soit non statique puisqu’elle lie toutes ses instances à la classe contenante.

En général, l’objet contenant veut accéder à ses membres. Par conséquent, nous devons stocker leurs références :

class Building { List<Room> rooms; class Room {} }

Notez, que tous les objets de classe interne stockent une référence implicite à leur objet contenant. Par conséquent, nous n’avons pas besoin de la stocker manuellement pour y accéder:

class Building { String address; class Room { String getBuildingAddress() { return Building.this.address; } } }

Aggrégation

L’agrégation est également une relation « has-a ». Ce qui la distingue de la composition, c’est qu’elle n’implique pas de posséder. Par conséquent, les cycles de vie des objets ne sont pas liés : chacun d’entre eux peut exister indépendamment des autres.

Par exemple, une voiture et ses roues. On peut enlever les roues, et elles existeront toujours. Nous pouvons monter d’autres roues (préexistantes), ou installer celles-ci sur une autre voiture et tout fonctionnera parfaitement.

Bien sûr, une voiture sans roues ou une roue détachée ne sera pas aussi utile qu’une voiture avec ses roues. Mais c’est pour cela que cette relation a existé en premier lieu : pour assembler les parties à une construction plus grande, qui est capable de plus de choses que ses parties.

Puisque l’agrégation n’implique pas de posséder, un membre n’a pas besoin d’être lié à un seul contenant. Par exemple, un triangle est constitué de segments. Mais les triangles peuvent partager des segments comme leurs côtés.

3.1. UML

L’agrégation est très similaire à la composition. La seule différence logique est que l’agrégation est une relation plus faible.

Par conséquent, les représentations UML sont également très similaires. La seule différence est que le losange est vide :

Pour les voitures et les roues, on ferait donc :

3.2. Code source

En Java, nous pouvons modéliser l’agrégation avec une bonne vieille référence :

class Wheel {}class Car { List<Wheel> wheels;}

Le membre peut être n’importe quel type de classe, à l’exception d’une classe interne non statique.

Dans l’extrait de code ci-dessus, les deux classes ont leur fichier source séparé. Cependant, nous pouvons également utiliser une classe interne statique:

class Car { List<Wheel> wheels; static class Wheel {}}

Notez que Java créera une référence implicite uniquement dans les classes internes non statiques. À cause de cela, nous devons maintenir la relation manuellement là où nous en avons besoin:

class Wheel { Car car;}class Car { List<Wheel> wheels;}

Association

L’association est la relation la plus faible entre les trois. Ce n’est pas une relation « a-un », aucun des objets n’est partie ou membre d’un autre.

L’association signifie seulement que les objets se « connaissent ». Par exemple, une mère et son enfant.

4.1. UML

En UML, on peut marquer une association avec une flèche :

Si l’association est bidirectionnelle, on peut utiliser deux flèches, une flèche avec une pointe de flèche aux deux extrémités, ou une ligne sans aucune pointe de flèche :

Nous pouvons représenter une mère et son enfant en UML, alors :

4.2. Code source

En Java, nous pouvons modéliser l’association de la même manière que l’agrégation :

class Child {}class Mother { List<Child> children;}

Mais attendez, comment savoir si une référence signifie agrégation ou association ?

Eh bien, on ne peut pas. La différence n’est que logique : si l’un des objets fait partie de l’autre ou non.

De plus, nous devons maintenir les références manuellement aux deux extrémités, comme nous l’avons fait avec l’agrégation :

class Child { Mother mother;}class Mother { List<Child> children;}

Note secondaire UML

Pour plus de clarté, nous voulons parfois définir la cardinalité d’une relation sur un diagramme UML. Nous pouvons le faire en l’écrivant aux extrémités de la flèche :

Notez, que cela n’a pas de sens d’écrire zéro comme cardinalité, car cela signifie qu’il n’y a pas de relation. La seule exception est lorsque nous voulons utiliser une plage pour indiquer une relation optionnelle :

Notez également, que puisque dans la composition il y a précisément un propriétaire, nous ne l’indiquons pas sur les diagrammes.

Un exemple complexe

Voyons un exemple (un peu) plus complexe !

Nous allons modéliser une université, qui a ses départements. Des professeurs travaillent dans chaque département, qui a aussi des amis entre eux.

Les départements existeront-ils après que nous ayons fermé l’université ? Bien sûr que non, donc c’est une composition.

Mais les professeurs existeront toujours (on l’espère). Nous devons décider ce qui est le plus logique : si nous considérons les professeurs comme faisant partie des départements ou non. Ou encore : sont-ils membres des départements ou non ? Oui, ils le sont. Il s’agit donc d’une agrégation. En plus de cela, un professeur peut travailler dans plusieurs départements.

La relation entre les professeurs est une association car cela n’a pas de sens de dire qu’un professeur fait partie d’un autre.

En conséquence, nous pouvons modéliser cet exemple avec le diagramme UML suivant :

Et le code Java ressemble à ceci :

class University { List<Department> department; }class Department { List<Professor> professors;}class Professor { List<Department> department; List<Professor> friends;}

Notez, que si nous nous appuyons sur les termes « has-a », « belongs-to », « member-of », « part-of », et ainsi de suite, nous pouvons plus facilement identifier les relations entre nos objets.

Conclusion

Dans cet article, nous avons vu les propriétés et la représentation de la composition, de l’agrégation et de l’association. Nous avons également vu comment modéliser ces relations en UML et en Java.

Comme d’habitude, les exemples sont disponibles sur GitHub.

Démarrez avec Spring 5 et Spring Boot 2, grâce au cours Learn Spring:

>> VERIFIER LE COURS

.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *