Héritage, composition et agrégation
Objectifs pédagogiques
- Comprendre les différences fondamentales entre héritage, composition et agrégation.
- Identifier les usages adaptés à chaque approche.
- Mettre en œuvre les bonnes pratiques pour une architecture maintenable et testable.
Héritage (extends)
L’héritage représente une relation "est-un" (is-a). Il est utilisé lorsqu’une classe spécialise ou étend une autre.
Avantages
- Partage de comportement.
- Réutilisation de code.
- Hiérarchie explicite.
Inconvénients
- Couplage fort entre classes.
- Moins flexible face aux changements.
- Difficile à tester isolément.
À utiliser quand :
- Les sous-types sont stables et bien définis.
- Il existe une hiérarchie logique simple.
- Les comportements sont communs et peu susceptibles d’évoluer.
Exemple
php
class Animal {
public function makeSound(): void {
echo "Generic sound";
}
}
class Dog extends Animal {
public function makeSound(): void {
echo "Bark";
}
}Composition
La composition est une relation "a-un". Un objet contient un ou plusieurs autres objets en tant qu’attributs.
Avantages
- Modulaire et interchangeable.
- Favorise la séparation des responsabilités.
- Facile à tester avec des mocks ou injections.
Inconvénients
- Demande une structure plus explicite.
- Peut paraître plus verbeux.
À utiliser quand :
- Les comportements peuvent changer dynamiquement.
- Vous voulez respecter les principes SOLID.
- Vous avez besoin de modularité forte.
Exemple
php
class Engine {
public function start(): void {
echo "Moteur allumé";
}
}
class Car {
private Engine $engine;
public function __construct(Engine $engine) {
$this->engine = $engine;
}
public function start(): void {
$this->engine->start();
}
}Agrégation
L’agrégation est une forme affaiblie de composition. L’objet agrégé peut vivre indépendamment de l’objet principal.
Avantages
- Couplage très faible.
- Facilite le partage d’objets entre entités.
Inconvénients
- Le lien logique est plus flou qu’en composition.
À utiliser quand :
- Vous modélisez une relation logique faible.
- Vous voulez éviter les dépendances fortes.
Exemple
php
class Player {}
class Team {
private array $players = [];
public function addPlayer(Player $player): void {
$this->players[] = $player;
}
}Comparatif
| Critère | Héritage | Composition | Agrégation |
|---|---|---|---|
| Relation | is-a | has-a | has-a (faible) |
| Couplage | Fort | Faible | Très faible |
| Reutilisabilité | Moyenne | Haute | Haute |
| Extensibilité | Limitée | Très bonne | Très bonne |
| Testabilité | Difficile | Facile | Très facile |
| Dynamisme du comportement | Rigide | Flexible | Flexible |
| Adapté pour DDD | ❌ | ✅ | ✅ |
| Cycle de vie lié | Oui | Oui (souvent) | Non |
Recommandations
- Privilégier la composition pour un design flexible et testable.
- Utiliser l’héritage avec parcimonie pour les modèles stables.
- Considérer l’agrégation pour les relations faibles et logiques.
Bonnes pratiques
- Ne jamais hériter juste pour réutiliser une méthode.
- Favoriser les interfaces pour définir des contrats.
- Injecter les dépendances pour améliorer la testabilité.
- Organiser les responsabilités selon les principes SOLID.