Le design pattern Decorator
Description
Le but du design pattern Decorator est d’ajouter dynamiquement des fonctionnalités supplémentaires à un objet. Cet ajout de fonctionnalités ne modifie pas l’interface de l’objet et reste donc parfaitement transparent vis-à-vis des clients.
Le design pattern Decorator constitue une alternative intéressante à la création d’une sous-classe pour enrichir le comportement d’un objet.
Exemple
Le système de vente de véhicules dispose d’une classe VueCatalogue qui affiche, sous la forme d’un catalogue électronique, les véhicules disponibles sur une page web.
Nous voulons maintenant afficher des données supplémentaires pour les véhicules "haut de gamme", à savoir des informations techniques liées au modèle. Pour réaliser l’ajout de cette fonctionnalité, nous pouvons réaliser une sous-classe d’affichage spécifique pour les véhicules "haut de gamme".
Si nous voulons afficher le logo de la marque des véhicules "moyen et haut de gamme", il va alors nous falloir ajouter une nouvelle sous-classe pour ces véhicules, surclasse de la classe des véhicules "haut de gamme", ce qui devient vite inutilement complexe. Il est aisé de comprendre ici que l’utilisation de l’héritage n’est pas une solution adaptée à ce qui est demandé, pour deux raisons :
-
L’héritage est un outil trop puissant pour réaliser un tel ajout de fonctionnalité.
-
L’héritage est un mécanisme statique.
Le design pattern Decorator propose une autre approche qui consiste à ajouter un nouvel objet appelé décorateur qui se substitue à l’objet initial tout en le référençant....
Structure
1. Diagramme de classes
La figure 13.4 détaille la structure générique du design pattern Decorator.
Figure 13.4 - Structure du design pattern Decorator
2. Participants
Les participants au design pattern decorator sont les suivants :
-
ComposantAbstrait (ComposantGraphiqueVehiculeInterface) est l’interface commune au composant et aux décorateurs.
-
ComposantConcret (VueVehicule) est l’objet initial auquel de nouvelles fonctionnalités doivent être ajoutées.
-
Decorateur (AbstractDecorateur) est une classe abstraite qui détient une référence vers un composant.
-
DecorateurConcretA et DecorateurConcretB (ModeleDecorateuret MarqueDecorateur) sont des sous-classes concrètes de AbstractDecorateur qui ont pour but l’implémentation des fonctionnalités ajoutées au composant.
3. Collaborations
Le décorateur se substitue totalement au composant. Lorsqu’il reçoit un message destiné à ce dernier, il le lui redirige en effectuant des opérations préalables ou postérieures.
Domaines d’application
Le design pattern Decorator peut être utilisé dans les domaines suivants :
-
Un système ajoute dynamiquement des fonctionnalités à un objet, sans modifier son interface, c’est-à-dire sans que les clients de cet objet doivent subir d’éventuelles modifications.
-
Un système gère des fonctionnalités qui peuvent être retirées dynamiquement.
-
L’utilisation de l’héritage pour étendre des objets ne constitue pas une solution pertinente, ce qui peut arriver quand leur hiérarchie est déjà suffisamment complexe.
Exemple en PHP
Nous présentons le code source PHP de l’exemple, en commençant par l’interface ComposantGraphiqueVehiculeInterface.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Decorator;
interface ComposantGraphiqueVehiculeInterface
{
public function affiche(): void;
}
La classe VueVehicule implémente la méthode affiche de l’interface ComposantGraphiqueVehiculeInterface.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Decorator;
class VueVehicule implements ComposantGraphiqueVehiculeInterface
{
public function affiche(): void
{
echo 'Affichage du véhicule' . PHP_EOL;
}
}
La classe AbstractDecorateur implémente également la méthode affiche en déléguant l’appel à son composant qui est une dépendance injectée dans son constructeur.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Decorator;
abstract class AbstractDecorateur implements
ComposantGraphiqueVehiculeInterface
{
protected ComposantGraphiqueVehiculeInterface $composant;
public function __construct(ComposantGraphiqueVehicule...