Appuyez sur Entrée pour voir vos résultats ou Echap pour annuler.

Patron de conception: Décorateur

Les sources de cet article sont disponibles sur GitHub.

Présentation

Voici le deuxième article sur la série traitant des patrons de conception. Dans le dernier article, il était question de la fabrique qui est un patron de création. Celui-ci traite d’un patron de structuration, soit le décorateur.

Adapteur, décorateur, façade… Confus?

Afin de bien comprendre le rôle du décorateur, il faut assimiler la différence entre ce dernier et les autres patterns qui sont, disons-le, très semblable, mais qui ont des cas d’utilisation différents.

Adapteur: Faire en sorte qu’un objet puisse être utilisé dans une méthode où sa signature ne correspond pas à ce dernier (faire fitter l’objet).

Décorateur: Ajouter des fonctionnalités à un objet.

Facade: Simplifier l’utilisation d’une interface.

Les 3 patrons de conception ont un point en commun: ils gardent une instance de la composante encapsulée.

Le décorateur (Decorator Pattern)

Comme mentionné ci-avant, le décorateur permet tout simplement d’ajouter des fonctionnalités à un objet. Ceci peut s’avérer très utile lors d’un phase de ingénierie d’un système ou lors d’ajout de nouvelles fonctionnalités et permettre notamment de faciliter le respect du principe de responsabilité unique et le principe ouvert/fermé des principes SOLID.

Le problème

Un exemple typique du décorateur vient de la programmation orientée aspect. Les aspects sont des bouts de code à exécuter à un certain moment lors de l’exécution d’un autre code. Ceci permet de, par exemple, ajouter de la journalisation d’appels d’une méthode.

Il serait tentant d’ajouter les lignes de journalisation directement dans la classe cible, sauf qu’on viendrait d’ajouter une fonctionnalité à cette classe:

  • Ce qu’elle fait déjà
  • La journalisation

De plus, on vient briser le principe ouvert/fermé en modifiant directement un objet au lieu d’en faire une sous-classe.

La solution

Bien entendu, le décorateur est notre solution! Mais comment l’implémenter? Supposons que nous avons une interface pour une classe d’affaires et que nous voulons ajouter de la journalisation à une de ces méthodes

L’implémentation concrète de cette interface pourrait être définie comme ceci:

À partir de cet instant, tout est en place pour créer le décorateur en charge de la journalisation. Ce qu’il faut savoir:

  1. Le décorateur et l’implémentation concrète de la classe à décorer doivent partager une même interface
  2. Le décorateur doit avoir une instance en attribut de la classe concrète à décorer
  3. Le code client instancie la classe concrète et la décore du décorateur

En se basant sur l’exemple ci-dessus, le décorateur ressemblerait à:

À l’exécution, il faut encapsuler la classe concrète dans le décorateur:

Conclusion

Encore une fois, les patrons de conception prouvent leur utilité. Ils permettent de faciliter le respect des principes OO et d’obtenir une application à l’épreuve du futur dans la mesure du possible. Quant à lui, le décorateur permet de bien découper les fonctionnalités en objets distincts et aux classes à décorer de rester inchangées, ce qui facilite le développement et le support.

N’hésitez pas à donner votre opinion dans les commentaires ci-dessous!

Code source

Les sources de cet article sont disponibles sur GitHub.

Suivez-nous par courriel!

Saisissez votre adresse courriel pour vous abonner au blog d'Ezo et recevoir une notification de chaque nouvel article par email.