Programmation • IoT

Résumé : Chapitre 6 – Composition et relations entre classes

Un programme orienté objet ne se construit pas uniquement avec des classes isolées ou reliées par héritage. Les objets doivent aussi collaborer et certains constituent naturellement des parties d’objets plus complexes. Une voiture, par exemple, n’est pas un moteur : elle possède un moteur. Cette différence conduit à la composition, qui permet à une classe de contenir directement un objet appartenant à une autre classe.

Dans une composition, l’objet membre fait réellement partie de l’objet qui le contient. Le moteur contenu dans une voiture conserve son propre type, son comportement et son encapsulation : la voiture ne peut pas accéder directement à ses données privées. Elle utilise son interface publique et peut ainsi lui déléguer certaines tâches, comme fournir sa puissance, sans connaître sa représentation interne.

Cette relation lie également les durées de vie. Avant qu’une voiture puisse exister, son moteur et ses autres composants doivent déjà avoir été construits. Ils sont donc initialisés dans la liste d’initialisation du constructeur, par exemple avec : moteur(puissance). Une affectation placée dans le corps arriverait trop tard, car elle supposerait que le moteur a déjà été construit.

Lorsqu’une classe contient plusieurs objets, leur ordre de construction est fixé par leur ordre de déclaration dans la classe, et non par l’ordre écrit dans la liste d’initialisation. Il est donc préférable de conserver le même ordre dans les deux endroits afin que le code reflète les opérations réellement effectuées et n’introduise pas de dépendances trompeuses.

La destruction suit le chemin inverse. Le corps du destructeur de l’objet contenant est exécuté, puis ses membres sont détruits automatiquement dans l’ordre opposé à leur construction. Cette gestion automatique constitue un avantage essentiel de la composition : lorsque les composants sont stockés directement, leur durée de vie suit naturellement celle de l’ensemble.

Le choix entre composition et héritage doit venir du modèle représenté, et non de ce que le compilateur accepte. L’héritage exprime une relation « est un » et permet la substitution : un carré est une forme. La composition exprime une relation « possède un » : une voiture possède une batterie, mais ne peut pas être considérée comme une batterie. Un héritage techniquement valide peut donc rester conceptuellement faux.

La composition aide aussi à répartir les responsabilités. Au lieu de concentrer dans Voiture la puissance, la capacité électrique, le freinage et la climatisation, chaque composant peut gérer son propre état et ses propres opérations. La voiture coordonne alors plusieurs objets spécialisés. Les classes deviennent plus simples, plus cohérentes et plus faciles à faire évoluer séparément.

La situation change lorsqu’une classe conserve seulement un pointeur ou une référence vers un objet. Si la voiture crée elle-même un moteur avec new, elle doit en organiser la destruction dans cette approche classique. Si elle reçoit l’adresse d’un moteur créé ailleurs, elle l’utilise sans nécessairement le posséder : cet objet peut continuer à exister indépendamment. Cette relation plus faible porte le nom d’agrégation.

Un pointeur classique indique uniquement où se trouve un objet ; il ne précise ni qui en est propriétaire ni qui doit le détruire. La distinction entre composition et agrégation ne dépend donc pas de la seule présence d’un pointeur, mais de la responsabilité et de la durée de vie prévues par la conception. Une erreur sur ce point peut provoquer une fuite de mémoire, une double destruction ou l’utilisation d’un objet qui n’existe plus.

Le chapitre fournit finalement trois questions pour organiser les relations entre classes : l’objet « est-il un » autre objet, auquel cas l’héritage convient ; « possède-t-il » un composant dont la durée de vie lui est liée, ce qui conduit à la composition ; ou « utilise-t-il » un objet indépendant, ce qui correspond à l’agrégation. Ces relations peuvent coexister dans une même architecture et permettent de construire des systèmes complexes par assemblage d’objets aux responsabilités bien définies.