The decorator pattern helps to add behavior or responsibilities to an object. This is also called “Wrapper”.

Examples

To do:
Find examples.

Cost

This pattern can be very expensive. You should only use it when it is really necessary. You should have lots of different behaviors and responsibilities for the same class.

Creation

This pattern is expensive to create.

Maintenance

This pattern can be expensive to maintain. If the representation of a class often changes, you will have lots of refactoring.

Removal

This pattern is hard to remove too.

Advises

Put the decorator term in the name of the decorator classes to indicate the use of the pattern to the other developers.

Implementations

Implementation in C#

This example illustrates a simple extension method for a bool type.

usingSystem;// Extension methods must be parts of static classes.staticclassBooleanExtensionMethodSample{publicstaticvoidMain(){boolyes=true;boolno=false;// Toggle the booleans! yes should return false and no should return true.Console.WriteLine(yes.Toggle());Console.WriteLine(no.Toggle());}// The extension method that adds Toggle to bool.publicstaticboolToggle(thisbooltarget){// Return the opposite of the target.return!target;}}

// Class to be decoratedfunctionCoffee(){this.cost=function(){return1;};}// Decorator AfunctionMilk(coffee){this.cost=function(){returncoffee.cost()+0.5;};}// Decorator BfunctionWhip(coffee){this.cost=function(){returncoffee.cost()+0.7;};}// Decorator CfunctionSprinkles(coffee){this.cost=function(){returncoffee.cost()+0.2;};}// Here's one way of using itvarcoffee=newMilk(newWhip(newSprinkles(newCoffee())));alert(coffee.cost());// Here's anothervarcoffee=newCoffee();coffee=newSprinkles(coffee);coffee=newWhip(coffee);coffee=newMilk(coffee);alert(coffee.cost());

Implementation in Java

First Example (window/scrolling scenario)

The following Java example illustrates the use of decorators using the window/scrolling scenario.

// the Window abstract classpublicabstractclassWindow{publicabstractvoiddraw();// draws the WindowpublicabstractStringgetDescription();// returns a description of the Window}// extension of a simple Window without any scrollbarsclassSimpleWindowextendsWindow{publicvoiddraw(){// draw window}publicStringgetDescription(){return"simple window";}}

The following classes contain the decorators for all Window classes, including the decorator classes themselves.

// abstract decorator class - note that it extends WindowabstractclassWindowDecoratorextendsWindow{protectedWindowdecoratedWindow;// the Window being decoratedpublicWindowDecorator(WindowdecoratedWindow){this.decoratedWindow=decoratedWindow;}publicvoiddraw(){decoratedWindow.draw();//delegation}publicStringgetDescription(){returndecoratedWindow.getDescription();//delegation}}// the first concrete decorator which adds vertical scrollbar functionalityclassVerticalScrollBarDecoratorextendsWindowDecorator{publicVerticalScrollBarDecorator(WindowdecoratedWindow){super(decoratedWindow);}@Overridepublicvoiddraw(){super.draw();drawVerticalScrollBar();}privatevoiddrawVerticalScrollBar(){// draw the vertical scrollbar}@OverridepublicStringgetDescription(){returnsuper.getDescription()+", including vertical scrollbars";}}// the second concrete decorator which adds horizontal scrollbar functionalityclassHorizontalScrollBarDecoratorextendsWindowDecorator{publicHorizontalScrollBarDecorator(WindowdecoratedWindow){super(decoratedWindow);}@Overridepublicvoiddraw(){super.draw();drawHorizontalScrollBar();}privatevoiddrawHorizontalScrollBar(){// draw the horizontal scrollbar}@OverridepublicStringgetDescription(){returnsuper.getDescription()+", including horizontal scrollbars";}}

Here's a test program that creates a Window instance which is fully decorated (i.e., with vertical and horizontal scrollbars), and prints its description:

The output of this program is "simple window, including vertical scrollbars, including horizontal scrollbars". Notice how the getDescription method of the two decorators first retrieve the decorated Window's description and decorates it with a suffix.

Second Example (coffee making scenario)

The next Java example illustrates the use of decorators using coffee making scenario. In this example, the scenario only includes cost and ingredients.

// The abstract Coffee class defines the functionality of Coffee implemented by decoratorpublicabstractclassCoffee{publicabstractdoublegetCost();// returns the cost of the coffeepublicabstractStringgetIngredients();// returns the ingredients of the coffee}// extension of a simple coffee without any extra ingredientspublicclassSimpleCoffeeextendsCoffee{publicdoublegetCost(){return1;}publicStringgetIngredients(){return"Coffee";}}

The following classes contain the decorators for all Coffee classes, including the decorator classes themselves..

Here's a test program that creates a Coffee instance which is fully decorated (i.e., with milk, whip, sprinkles), and calculate cost of coffee and prints its ingredients:

publicclassMain{publicstaticfinalvoidmain(String[]args){Coffeec=newSimpleCoffee();System.out.println("Cost: "+c.getCost()+"; Ingredients: "+c.getIngredients());c=newMilk(c);System.out.println("Cost: "+c.getCost()+"; Ingredients: "+c.getIngredients());c=newSprinkles(c);System.out.println("Cost: "+c.getCost()+"; Ingredients: "+c.getIngredients());c=newWhip(c);System.out.println("Cost: "+c.getCost()+"; Ingredients: "+c.getIngredients());// Note that you can also stack more than one decorator of the same typec=newSprinkles(c);System.out.println("Cost: "+c.getCost()+"; Ingredients: "+c.getIngredients());}}

Window System

# the Window base classclassWindow(object):defdraw(self,device):device.append('flat window')definfo(self):pass# The decorator pattern approchclassWindowDecorator:def__init__(self,w):self.window=wdefdraw(self,device):self.window.draw(device)definfo(self):self.window.info()classBorderDecorator(WindowDecorator):defdraw(self,device):self.window.draw(device)device.append('borders')classScrollDecorator(WindowDecorator):defdraw(self,device):self.window.draw(device)device.append('scroll bars')deftest_deco():# The way of using the decorator classesw=ScrollDecorator(BorderDecorator(Window()))dev=[]w.draw(dev)printdevtest_deco()

Difference between subclass method and decorator pattern

# The subclass approchclassBorderedWindow(Window):defdraw(self,device):super(BorderedWindow,self).draw(device)device.append('borders')classScrolledWindow(Window):defdraw(self,device):super(ScrolledWindow,self).draw(device)device.append('scroll bars')# combine the functionalities using multiple inheritance.classMyWindow(ScrolledWindow,BorderedWindow,Window):passdeftest_muli():w=MyWindow()dev=[]w.draw(dev)printdevdeftest_muli2():# note that python can create a class on the fly.MyWindow=type('MyWindow',(ScrolledWindow,BorderedWindow,Window),{})w=MyWindow()dev=[]w.draw(dev)printdevtest_muli()test_muli2()

Dynamic languages

The decorator pattern can also be implemented in dynamic languages either with interfaces or with traditional OOP inheritance.