Le design pattern Decorator (en français, décorateur) a pour but d’étendre les fonctionnalités d’un objet grâce à l’utilisation de l’héritage. Mon père m’a toujours dit que d’un âne, on ne pouvait pas faire un cheval de course; je vais m’employer à lui donner tort ! Voici un diagramme de classe qui sert de base à notre exemple, je l’ai réalisé avec l’outil ArgoUML sur GNU/LInux Debian :
Au sommet de notre diagramme trône fièrement la classe abstraite Equide : elle possède une variable d’instance protégée de type chaîne de caractères qui stocke une description très sommaire de l’équidé ainsi que deux méthodes dont une (donne Description) est abstraite. Voici son code en détail :
abstract class Equide { protected $_description = 'équidé commun'; abstract public function courir(); public function donneDescription() { return $this->_description; } }
Ce super-type est dérivé en deux classes concrètes :
class AneSauvage extends Equide { public function __construct() { $this->_description = 'âne sauvage'; } public function courir() { echo "Il m'arrive de courir à l'occasion..."; } } class AneDomestique extends Equide { public function __construct() { $this->_description = 'âne domestique'; } public function courir() { echo "Si vraiment on m'y oblige, je trotte..."; } }
La méthode courir, signalée abstraite dans la mère est implémentée dans les filles et la valeur par défaut stockée dans la variable d’instance _description est écrasée avec une valeur un peu plus censée lors de la construction de l’objet.
La nouveauté arrive maintenant…
abstract class DecorateurEquide extends Equide { protected $_equide; public function __construct(Equide $equide) { $this->_equide = $equide; } } class ChevalDeCourse extends DecorateurEquide { public function donneDescription() { return $this->_equide->donneDescription() . ' qui court très très vite !' . PHP_EOL; } public function courir() { return $this->_equide->courir() . ' et maintenant je galope tel un cheval de course !' . PHP_EOL; } }
Notre classe décorateur est DecorateurEquide; voyez-le par vous-mêmes, c’est une classe abstraite…il faudra donc la dériver. Cette classe prend en composition un objet de la classe Equide, puisque c’est précisément cet objet qu’elle va décorer ! C’est lors de l’instanciation d’une de ses classes filles que l’on passera notre instance d‘Equide au constructeur.
La seule classe fille d’Equide dans notre exemple est ChevalDeCourse; elle ajoute des fonctionnalités aux méthodes courir et donneDescription qui proviennent de DecorateurEquide et donc de Equide. Dans ce cet exemple trivial ces fonctionnalités se résument à une simple chaîne de caractères.
Les décorateurs ont le même type que les objets qu’ils décorent, c’est la raison pour laquelle DecorateurEquide hérite d’Equide, pour en être un sous-type ! L’héritage n’est pas réalisé à des fins « comportementales » mais simplement pour des raisons de typage. J’ai mis la variable d’instance _equide et le constructeur dans DecorateurEquide mais j’aurais pu tout aussi bien laisser cette classe vide (ne m’en servir vraiment que pour le typage) et déporter ce code dans les classes concrètes qui spécialisent (et spécialiseront à terme) DecorateurEquide. C’est un choix de conception parmi d’autres…
Pour utiliser ce code :
$aneDomestique = new AneDomestique; $cheval = new ChevalDeCourse($aneDomestique); echo $cheval->donneDescription(); echo $cheval->courir();
Tu vois Papa, c’est bien la preuve que d’un âne, on peut faire un cheval de course !
Source : blog Terapias Naturales
Merci beaucoup pour votre article, c’est très bien expliqué, et en plus c’est marrant 😉
Et c’est juste maintenant que je découvre ce blog ! Je vais avoir de la lecture pour un bout de temps. xD
Toujours intéressant et amusant en 2022 :D; Merci
Explication simple, claire et amusante, bravo 🙂