Académique Documents
Professionnel Documents
Culture Documents
Décorateur
Alias : Emballeur, Empaqueteur, Wrapper, Decorator
Contenu premium
Intention
Patrons de conception
Décorateur est un patron de conception structurel qui permet d’affecter dynamiquement de
Introduction nouveaux comportements à des objets en les plaçant dans des emballeurs qui implémentent
ces comportements.
Catalogue
Patrons de création
Patrons structurels
Cet article est tiré de notre ebook
Patrons comportementaux
Plongée au cœur des
Exemples de code PATRONS DE CONCEPTION
Connexion
Nous contacter
Problème
Imaginez que vous travaillez sur une librairie qui permet aux programmes d’envoyer des
noti cations à leurs utilisateurs lorsque des événements importants se produisent.
La version initiale de la librairie était basée sur la classe Notificateur qui n’avait que
quelques attributs, un constructeur et une unique méthode envoyer . La méthode pouvait
prendre un message en paramètre et l’envoyait à une liste d’e-mails à l’aide du constructeur du
noti cateur. Une application externe qui jouait le rôle du client devait créer et con gurer
l’objet noti cateur une première fois, puis l’utiliser lorsqu’un événement important se
produisait.
Un programme peut utiliser la classe noti cateur a n d’envoyer des noti cations au sujet d’événements
importants à une liste prédé nie d’adresses e-mail.
Au bout d’un certain temps, vous vous rendez compte que les utilisateurs de la librairie veulent
plus que les noti cations qu’ils reçoivent sur leur boîte mail. Ils sont nombreux à vouloir
recevoir des SMS lorsque leurs applications rencontrent des problèmes critiques. Certains
voudraient être prévenus sur Facebook et les employés de certaines entreprises adoreraient
recevoir des noti cations Slack.
Chaque type de noti cation est implémenté dans une sous-classe du noti cateur.
Cela n’a pas l’air bien dif cile ! Vous avez étendu la classe Notificateur et ajouté des
méthodes de noti cation supplémentaires dans de nouvelles sous-classes.
Le client devait instancier la classe de noti cation désirée et utiliser cette instance pour toutes
les autres noti cations, mais quelqu’un a remis en question ce fonctionnement en vous
af rmant qu’il aimerait bien utiliser plusieurs types de noti cations simultanément. Si votre
maison prend feu, vous avez très certainement envie d’en être informé par tous les moyens
possibles.
Vous avez tenté de résoudre ce problème en créant des sous-classes spéciales qui combinent
plusieurs méthodes de noti cation dans une seule classe. Mais il s’avère que cette approche va
non seulement gon er le code de la librairie, mais aussi celui du client.
Vous devez structurer vos classes de noti cation différemment pour ne pas trop les multiplier,
sinon vous allez vous retrouver dans le livre Guinness des records.
Solution
La première chose qui nous vient à l’esprit lorsque l’on veut modi er le comportement d’un
objet, c’est d’étendre sa classe. Cependant, voici quelques mises en garde concernant
l’héritage :
L’héritage est statique. Vous ne pouvez pas modi er le comportement d’un objet au moment
de l’exécution. Vous ne pouvez que remplacer la totalité de l’objet par un autre, généré
grâce à une sous-classe différente.
Les sous-classes ne peuvent avoir qu’un seul parent. Dans la majorité des langages de
programmation, vous ne pouvez hériter que d’une seule classe à la fois.
Grâce à cette nouvelle approche, il est facile de remplacer l’objet référencé par un autre, ce qui
modi e le comportement du conteneur au moment de l’exécution. Un objet peut utiliser le
comportement de diverses classes, posséder des références à de nombreux objets et leur
déléguer toutes sortes de tâches. L’agrégation et la composition sont des principes clés dans le
décorateur, tout comme dans de nombreux autres patrons. Sur ces belles paroles, revenons à
nos moutons.
Héritage contre Agrégation.
À quel moment un emballeur devient-il réellement un décorateur ? Comme je l’ai déjà dit, un
emballeur implémente la même interface que l’objet emballé. Du point de vue du client, ces
objets sont identiques. L’attribut de la référence de l’emballeur doit pouvoir accueillir n’importe
quel objet qui implémente cette interface. Vous pouvez ainsi utiliser plusieurs emballeurs sur
un seul objet et lui attribuer les comportements de plusieurs emballeurs en même temps.
Reprenons notre exemple et mettons-y une noti cation par e-mail dans la classe de base
Notificateur , mais transformons toutes les autres méthodes de noti cation en décorateurs.
Le code client doit emballer un objet basique Noti cateur pour le transformer en un ensemble
de décorateurs adapté aux préférences du client. Les objets qui en résultent sont empilés.
Les applications peuvent con gurer des piles complexes de décorateurs pour les noti cations.
Le client traite le dernier objet de la pile. Les décorateurs implémentent tous la même
interface (le noti cateur de base). Le reste du code client manipule indifféremment l’objet
noti cateur original et l’objet décoré.
Nous pouvons utiliser cette technique pour tous les autres comportements, comme la mise en
page des messages ou la création de la liste des destinataires. Le client peut décorer l’objet
avec des décorateurs personnalisés tant qu’ils suivent la même interface que les autres.
Analogie
Porter des vêtements est un bon exemple d’utilisation. Si vous avez froid, vous vous enroulez
dans un pull. Si vous avez encore froid, vous pouvez porter un blouson par-dessus. S’il pleut,
vous en lez un imperméable. Tous ces vêtements « étendent » votre comportement de base
mais ne font pas partie de vous, et vous pouvez facilement enlever un vêtement lorsque vous
n’en avez plus besoin.
Structure
5 Le Client peut emballer les composants dans
plusieurs couches de décorateurs, tant qu’il
manipule les objets à l’aide de l’interface du
1
composant.
Le Composant déclare
l’interface commune pour
les décorateurs et les
objets décorés.
3 Le Décorateur de Base possède un attribut
pour référencer un objet emballé. L’attribut
doit être déclaré avec le type de l’interface du
2
composant a n de contenir à la fois les
Le Composant Concret est composants concrets et les décorateurs. Le
une classe contenant des décorateur de base délègue toutes les
objets qui vont être opérations à l’objet emballé.
emballés. Il dé nit le
comportement par défaut
qui peut être modi é par
les décorateurs.
Pseudo-code
Dans cet exemple, le Décorateur permet la compression et le chiffrage des données
indépendamment du code qui les utilise.
L’application emballe l’objet de la source de données à l’aide de deux décorateurs. Ils modi ent
la manière dont les données sont lues et écrites sur le disque :
Les décorateurs chiffrent et compressent les données juste avant qu’elles soient écrites sur
le disque. La classe d’origine écrit les données chiffrées et protégées dans le chier sans
savoir qu’il y a eu une modi cation.
Une fois que les données sont lues depuis le disque, elles repassent dans ces mêmes
décorateurs qui les décompressent et les déchiffrent.
method writeData(data) is
// Écrit les données dans le fichier.
method readData():data is
// Lit les données du fichier.
method readData():data is
// 1. Récupère les données de la méthode emballée
// lireDonnées.
// 2. La déchiffre si besoin.
// 3. Retourne le résultat.
method readData():data is
// 1. Récupère les données de la méthode emballée
// lireDonnées.
// 2. La décompresse si besoin.
// 3. Retourne le résultat.
method load() is
return source.readData()
method save() is
source.writeData(salaryRecords)
// ...d’autres méthodes utiles...
Possibilités d’application
Utilisez le décorateur si vous avez besoin d’ajouter des comportements supplémentaires au
moment de l’exécution sans avoir à altérer le code source de ces objets.
interdire l’héritage une classe. Le seul moyen d’étendre le comportement d’une telle classe
est de l’emballer en utilisant un décorateur.
Mise en œuvre
1. Assurez-vous que votre domaine peut être représenté sous la forme d’un composant
principal recouvert par plusieurs couches facultatives.
3. Créez une classe concrète pour le composant et dé nissez son comportement de base.
4. Créez une classe de base décorateur. Elle doit inclure un attribut qui va permettre de
stocker la référence à un objet emballé. Cet attribut doit être déclaré avec le type de
l’interface du composant, a n de le relier aux composants concrets et aux décorateurs. Le
décorateur de base doit déléguer tout le travail à l’objet emballé.
7. Le code client doit être responsable de la création des décorateurs et de leur agencement
en fonction des besoins du client.
Avantages et inconvénients
Vous pouvez étendre le comportement Retirer un emballeur spéci que de la
d’un objet sans avoir recours à la pile n’est pas chose aisée.
création d’une nouvelle sous-classe.
Il n’est pas non plus aisé de mettre en
Vous pouvez ajouter ou retirer place un décorateur dont le
dynamiquement des responsabilités à un comportement ne varie pas en fonction
objet au moment de l’exécution. de sa position dans la pile.
L’Adaptateur procure une interface différente à l’objet emballé, la Procuration lui fournit la
même interface et le Décorateur lui met à disposition une interface améliorée.
Un décorateur est comme un composite, mais avec un seul composant enfant. Il y a une
autre différence importante : Le décorateur ajoute des responsabilités supplémentaires à
l’objet emballé, alors que le composite se contente d’« additionner » les résultats de ses
enfants.
Mais ces patrons de conception peuvent également coopérer : vous pouvez utiliser le
décorateur pour étendre le comportement d’un objet spéci que d’un arbre Composite.
Les conceptions qui reposent énormément sur le Composite et le Décorateur tirent des
avantages à utiliser le Prototype. Il vous permet de cloner les structures complexes plutôt
que de les reconstruire à partir de rien.
Le Décorateur vous permet de changer la peau d’un objet, alors que la Stratégie vous
permet de changer ses tripes.
Exemples de code
En savoir plus…
RETOUR SUIVANT
Composite Façade