En la programació orientada a objectes, el patró Decorator (alternativament conegut com a Wrapper, un nom amb què també és conegut el patró Adaptador) és un patró de disseny que permet afegir un comportament a un objecte, tant estàticament com dinàmicament, sense que la resta d'objectes de la mateixa classe vegin alterat el seu comportament
[1] El patró Decorator és útil sovint per complir el principi de responsabilitat única, car permet dividir una funcionalitat en diverses classes amb una única àrea d'afectació.[2]
Propòsit
El patró Decorator s'utilitza per estendre (decorar) la funcionalitat d'un cert objecte de forma estàtica, o en alguns casos en temps d'execució, independentment de la resta d'instàncies de la mateixa classe, en el cas que hagi estat dissenyat prèviament. Aquest comportament s'aconsegueix dissenyant una classe decorator nova que encapsuli la classe original. Aquest encapsulament es podria aconseguir seguint els següents passos:
Afegir una subclasse de la classe "Component" original en una "classe" Decorator (com es pot observar en l'esquema UML).
Afegir un punter a Component en forma de camp en la classe de Decorator.
Passar per paràmetres un Component al constructor Decorator per inicialitzar el punter de Component.
En la classe Decorator, redireccionar tots els mètodes de "Component" al punter "Component".
Sobreescriure qualsevol mètode de Component que es necessiti modificar el seu comportament en la classe ConcreteDecorator.
Aquest patró està dissenyat de manera que múltiples decoradors poden ser apilats un sobre l'altre, cada cop afegint-hi una nova funcionalitat al(s) mètode(s) sobreescrit(s).
S'entén que els decoradors i l'objecte de la classe original compartiran un conjunt de característiques comunes. En l'esquema anterior, el mètode "operation()" està disponible tant en la versió decorada com en la no decorada.
Les característiques del Decorator (per exemple, mètodes, propietats, o d'altres membres) estan definides normalment per un interfície, per mixin o per l'herència de classes que és compartida pels decorators i l'objecte decorat. En l'exemple anterior, la classe "Component" és heretada tant per "ConcreteComponent" com per la subclasse que descendeix de "Decorador".
El patró Decorator és una alternativa a l'herència. L'herència afegeix comportament en temps de compilació i el canvi afecta a totes les instàncies de la classe original; fet que difereix del Decorator que proporciona un nou comportament en temps d'execució en objectes concrets.
Exemple
El següent exemple Java ambientat en la preparació de cafè il·lustra l'ús de decoradors. En aquest exemple només es tenen en compte costos i ingredients.
// La classe abstracta Cafe defineix la funcionalitat de Cafe implementada pel decoradorpublicabstractclassCafe{publicabstractdoublegetCost();// Retorna el cost del cafèpublicabstractStringgetIngredients();// Retorna els ingredients del cafè}// Extensió d'un simple "Cafe" sense cap ingredient extrapublicclassCafeSimpleextendsCafe{publicdoublegetCost(){return1;}publicStringgetIngredients(){return"Cafè";}}
La següent classe conté els decoradors per totes les classes Cafè, heretant les classes decorador pròpies.
// Classe abstracte Decorator - fixi-se que estén de la classe abstracta CafepublicabstractclassCafeDecoratorextendsCafe{protectedfinalCafeCafeDecorator;publicCafeDecorator(Cafec){this.cafeDecorat=c;}publicdoublegetCost(){// Implementació dels mètodes de la classe abstractareturncafeDecorat.getCost();}publicStringgetIngredients(){returncafeDecorat.getIngredients();}}// Decorator AmbLlet barreja llet amb cafè.// Fixi's que estén de CafeDecorator.classAmbLletextendsCafeDecorator{publicAmbLlet(Cafec){super(c);}publicdoublegetCost(){// Substitució de mètode definit en la [[superclasse]] abstractareturnsuper.getCost()+0.5;}publicStringgetIngredients(){returnsuper.getIngredients()+", Llet";}}// Decorator AmbEncenallsXocolata barreja encenalls de xocolata amb el cafè.// Fixi-se que estén CafeDecorator.classAmbEncenallsXocolataextendsCafeDecorator{publicAmbEncenallsXocolata(Cafec){super(c);}publicdoublegetCost(){returnsuper.getCost()+0.2;}publicStringgetIngredients(){returnsuper.getIngredients()+", Encenalls de xocolata";}}
El següent tros de codi és el programa que crea una instància Cafe que està totalment decorada (amb llet i encenalls de xocolata), i calcula el cost del cafè i mostra els seus ingredients: