Le Design Pattern Decorateur (Decorator) en PHP

Le décorateur est un Modèle de Conception relativement proche de l’Adaptateur, bien qu’il ne serve pas les mêmes objectifs.

Comme l’adaptateur, le décorateur va agréger l’objet décoré. Le but n’est toutefois pas ici d’adapter le fonctionnement de l’objet décoré, mais d’en étendre les possibilités. C’est un peu comme de l’héritage…. mais sans passer par de l’héritage (nous reviendrons dessus plus loin).

Exposé de l’exemple

Vous disposez de classes de Logs sous divers formats tels que

interface ILog {
   public function add ($logInformations);
}
class LogFile extends Log {/* implémentation */}
 class LogCSV extends LogFile {/* implémentation */}
 class LogXML extends LogFile {/* implémentation */}
class LogDB extends Log {/* implémentation */}

Vous souhaitez disposer, pour chaque classe de Log Fille, de la possibilité d’envoyer des alertes par mail.

Solution sans le Décorateur

Sans le décorateur, vous pouvez ajouter une classe abstraite aux différents types de Log et y ajouter le nouveau comportement.

Le problème est que toutes les classes de log, même si elles savent toutes tracer une information, ne disposent pas forcément d’un ancêtre commun. (On pourrait très bien décider qu’un objet imprimante, un écran, une base de données, un fichier, une adresse mail, la console, … implémentent l’interface ILog sans qu’on puisse vraiment leur trouver un point commun justifiant d’un héritage).

En poussant l’exemple plus loin, un écran d’ordinateur et un écrivain savent tous les deux afficher du texte (et donc savent implémenter l’interface « écriture »), mais il reste difficile de justifier d’un ancêtre commun…. e il en va de même avec un piano et une enceinte qui tous les deux peuvent jouent des notes de musique… vous avez compris l’idée.

De plus, aujourd’hui nous ajoutons un comportement d’alerte, demain nous souhaiterons peut être ajouter un comportement de filtrage, un comportement de formatage, un comportement d’ajout d’informations, peut être même que nous voudrons mélanger le tout….. bref, nous nous retrouverions avec une interface ILog démesurée ou avec une classe abstraite magique.

Solution avec le Décorateur

Créons maintenant notre classe de décoration.

/**
 * La classe décoratrice respecte elle aussi l'interface attendue par les clients
 */
class AlertLogDecorator implements ILog {
   private $_decorated;

   public function __construct (ILog $pDecorated){
      $this->_decorated = $pDecorated;
   }

   public function add ($logInformations){
      //réalisation du comportement spécifique, et de l'alerte
      //...

      //on délègue maintenant à l'objet la réalisation
      //de la tâche initial
      $this->_decorated->add ($logInformations);
   }
}

Le décorateur, comme on le voit, ressemble trait pour trait à l’adaptateur, c’est son objectif qui diffère.

Exemple d’utilisation du décorateur

$log = LoggerFactory::create ('journal principal');
$log->add ('Lancement applicatif');

Encore une fois, coté client, l’utilisation de la fabrique masque la complexité de l’instanciation de l’objet décoré.

Voici le code possible de la fabrique

class LoggerFactory {
   public static function create ($type){
      //retourne le nom de l'objet à utiliser
      $logClass = self::getClass ($type);
      //création de l'objet
      $logObject = new $logClass ();

      if (self::getOption ('alerte', $type)){
         $logObject = new AlertLogDecorator ($logObject);
      }

      if (self::getOption ('logTime', $type)){
         $logObject = new AppendTimeDecorator ($logObject);
      }

      if (self::getOption ('debugBackTrace', $type)){
         $logObject = new AppendDebugBackTraceDecorator ($logObject);
      }

      //et ainsi de suite
      return $logObject;
   }
}

6 réflexions au sujet de « Le Design Pattern Decorateur (Decorator) en PHP »

  1. Ping : Autoloader Universel – Jouons avec les Patterns | Gerald's Blog

  2. Salut,
    Je viens de lire ton article sur le patron de conception Décorateur et il y a un passage que ne je ne comprends pas bien, il s’agit de la définition de la classe AlertLogDecorator.
    Je ne vois pas ce que représente la propriété $_log à la ligne 8. Est-ce qu’il ne s’agirait pas de la propriété $_decorated ? Ou alors j’ai loupé quelque chose. 🙂
    Sinon merci pour cet article car j’ai l’impression que les infos sur les décorateurs en PHP ne sont pas nombreuses.
    Bonne continuation.

  3. Ping : Les registres (Registry) en PHP | Gerald's Blog

  4. Ping : De l’usage des méthodes statiques | Gerald's Blog

  5. Ping : Aperçu des composants Symfony2: HttpKernel | Dev & Co

Laisser un commentaire

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