PTOM: The Decorator Pattern


For the month of November, Pablo's Topic of the Month is Design Patterns. I will be talking about the Decorator design pattern in this post.

The Decorator Pattern was originally coined by The Gang Of Four (GoF). It is a commonly used pattern for extending functionality dynamically at runtime. This is in contrast to a common OOP technique that everyone knows called inheritance. At it's most basic level, think of the Decorator pattern as a wrapper with the intent to modify/attach additional behavior to an underlying class.

This is one of the easiest patterns to grasp and understand, as well as to put to use. We will use an example of a coffee shop, let's start with a class that is used to represent a cup of coffee available in the shop. Here we have the ICoffee and Coffe interface and class:

public interface ICoffee
{
    string Name { get; }
    decimal Total { get; }
}
 
public class Coffee : ICoffee
{
    public string Name
    {
        get { return "Coffee"; }
    }
 
    public decimal Total
    {
        get { return 0.75m; }
    }
}


We have an interface that defines behavior for a cup of Coffee, and then we have a concrete class that represents a Coffee. Something to take note of here is the fact that the GoF sample uses an abstract base class for Coffee instead of my ICoffee interface. The abstract base class is then also used when implementing the decorator pattern. In other samples, people use interfaces instead of ABC's, I usually opt for interfaces to start and then refactor to ABC if it is warranted. Use your judgement here. This is a pretty basic example so an ABC isn't really needed.

Now let's say we want to add the ability to have a customer add an extra shot of espresso to their latte. Normally you would do this with traditional inheritance like so:

public class CoffeePlusEspresso : Coffee
{
    public new decimal Total
    {
        get { return base.Total + .5m; }
    }
    public new string Name
    {
        get { return string.Format("{0} w/ Extra shot of espresso", base.Name); }
    }
}

This would work, however it's not very desirable. Eventually as you add more and more permutations, (Coffee w/ Espresso, Coffee w/ Espress and Whip cream, etc..) it would lead to a class explosion and you would have a new class for every new combination of ingredients someone could have for a cup of coffee. A better option would be if we could add or "decorate" the original cost and name with our added options. Enter the Decorator Pattern.

The first step in implementing the decorator pattern is to define an abstract base class that all of your decorators can derive from. This helps enforce the DRY principle by having the code that implements the ICoffee interface. Commonly, this ABC will only be calling the passed in or "decorated" object. This way, you only need to extend the properties/methods you want in the decorators and eliminates the need to return the decorated properties/methods in each decorator.

Here is our base class that I have called IngredientDecorator:

public abstract class IngredientDecorator : ICoffee
{
    protected ICoffee _decoratedCoffee;
 
    protected IngredientDecorator(ICoffee decoratedCoffee)
    {
        _decoratedCoffee = decoratedCoffee;
    }
 
    public virtual string Name
    {
        get { return _decoratedCoffee.Name; }
    }
 
    public virtual decimal Total
    {
        get { return _decoratedCoffee.Total; }
    }
}

As you can see here, our base decorator implements the ICoffee interface by just calling the underlying ICoffee properties that we passed in the constructor. Very simple and to the point. Now we can start to create our concrete decorators that will extend the behavior of our Coffee class. Lets start with our original Espresso example and create an EspressoShotDecorator class.

public class EspressoShotDecorator : IngredientDecorator
{
    public EspressoShotDecorator(ICoffee decoratedCoffee) : base(decoratedCoffee)
    {
    }
 
    public override string Name
    {
        get { return string.Format("{0}, shot of espresso", base.Name); }
    }
 
    public override decimal Total
    {
        get { return base.Total + 0.50m; }
    }
}

We can now create a Coffee instance, pass it to an EspressoShotDecorator and print out the grand total and modified name by calling EspressoShotDecorator.Name/EspressoShotDecorator.Total as shown here:

Coffee plainCoffee = new Coffee();
EspressoShotDecorator espressoShotDecorator = new EspressoShotDecorator(plainCoffee);
 
Console.WriteLine("Name of your coffee: {0}", espressoShotDecorator.Name);
Console.WriteLine("Cost: {0}", espressoShotDecorator.Total);
 
// Name of your coffee: Coffee, shot of espresso
// Cost: 1.25

This is where it starts to become really flexible. Let's say we also have a "Whip Cream" topping that we want to add as an ingredient. To add this functionality to our application, all we need to do is create a class that represents that single item and we can then begin to chain together the options when someone is asking for their cup of coffee with additional options. The options they have are now interchangable and dynamic. Here is the WhipCreamDecorator:

public class WhipCreamDecorator : IngredientDecorator
{
    public WhipCreamDecorator(ICoffee decoratedCoffee) : base(decoratedCoffee)
    {
    }
 
    public override string Name
    {
        get { return string.Format("{0}, whip cream", base.Name); }
    }
 
    public override decimal Total
    {
        get { return base.Total + 0.25m; }
    }
}

Adding this to the mix and then chaining it on top of the EspressoShotDecorator would yield the following results:

WhipCreamDecorator whipCreamDecorator = new WhipCreamDecorator(espressoShotDecorator);
 
Console.WriteLine("Name of your coffee: {0}", whipCreamDecorator.Name);
Console.WriteLine("Cost: {0}", whipCreamDecorator.Total);
 
// Name of your coffee: Coffee, shot of espresso, whip cream
// Cost: 1.50

You can now see how this can be flexible in dynamically modifying and extending behavior at runtime. If you want to be really cool, you can hook up the classes to an IoC framework and chain together these objects through a configuration. This is even more flexible than the above approach because you could modify behavior by changing your configuration for the IoC framework. An excellent example of this was already posted by Alex Henderson (a.k.a The Bitter Coder) in his series on Castle Windsor tutorials

As you can see the Decorator Pattern is a powerful, easy to use/implement, flexible design pattern that should be in everyones arsenal. Please post comments any derivations that you have found useful of the Decorator Pattern. Till next time!


Posted Nov 16 2008, 11:23 PM by schambers

Comments

Dave the Ninja wrote re: PTOM: The Decorator Pattern
on 11-17-2008 12:34 AM

I always think the decorator pattern is very similar to the Adapter pattern.

Both very very useful patterns.

Great article!

Dave the Ninja

schambers wrote re: PTOM: The Decorator Pattern
on 11-17-2008 6:56 AM

@Dave

The decorator is similar in behavior to the adapter pattern. The main difference being the intent of the adapter is to change one interface into another in order to be able to work with a system that you couldn't normally work with.

While the structure is similar, the intent is different.

Thanks for the kind words!

Steve wrote re: PTOM: The Decorator Pattern
on 11-17-2008 6:56 AM

Excellent post - thank you for explaining the decorator pattern.

Question: is there concern of an 'explosion of decorator classes' ?

Dew Drop - November 17, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - November 17, 2008 | Alvin Ashcraft's Morning Dew
on 11-17-2008 6:58 AM

Pingback from  Dew Drop - November 17, 2008 | Alvin Ashcraft's Morning Dew

Decorator Pattern at { null != Steve } wrote Decorator Pattern at { null != Steve }
on 11-17-2008 8:12 AM

Pingback from  Decorator Pattern at { null != Steve }

schambers wrote re: PTOM: The Decorator Pattern
on 11-17-2008 8:38 AM

@Steve

I suppose you could say that is a concern, but an acceptable concern. You would need to contain the additional logic somewhere. One class per behavior would be acceptable in my eyes.

Brad Mead wrote re: PTOM: The Decorator Pattern
on 11-17-2008 12:09 PM

Good example... Thanks for a novel context (Coffee) in which to couch the understanding.

Mike wrote re: PTOM: The Decorator Pattern
on 11-17-2008 2:46 PM

Great post! very clear example, I posted about an example of employing decorator to add extra behaviour a while back journalofasoftwaredev.wordpress.com/.../multi-search-engine-enhancement-using-design-patterns be interesting to see what you think :)

Pat wrote re: PTOM: The Decorator Pattern
on 11-17-2008 2:50 PM

Suppose your object model was a little more deep than just ICoffee:

ICoffee <- ILatte <- IX <- IY <- IZ

Whip cream, chocolate, etc. could only be added to IZ and not ICoffee directly. The decorator provides dynamic extensibility which is nice, but now something that decorates IZ has to also wrap all members of ICoffee, ILatte, IX, and IY.

If any aspect of that hierarchy changes, your decorator has to be updated. Does this present a maintenance issue? Are their ways to work around this?

Arjan`s World » LINKBLOG for November 17, 2008 wrote Arjan`s World &raquo; LINKBLOG for November 17, 2008
on 11-17-2008 3:27 PM

Pingback from  Arjan`s World    » LINKBLOG for November 17, 2008

Ray Houston wrote Pablo's Topic of the Month - November: Design Patterns
on 11-17-2008 9:20 PM

Pablo's Topic of the Month - November: Design Patterns Back in April, we announced we would be doing

Reflective Perspective - Chris Alcock » The Morning Brew #225 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #225
on 11-17-2008 9:57 PM

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #225

schambers wrote re: PTOM: The Decorator Pattern
on 11-18-2008 3:29 AM

@Pat

I suppose if your graph is that deep, then the easiest way to accomplish that is still with ABC's for the base decorator.

This is a good question though. While I have not had decorators that were that complex heirarchy wise, I would be interested if anyone else has come across a situation like that.

Ed wrote re: PTOM: The Decorator Pattern
on 11-18-2008 5:18 PM

@ Brad Mead

Not really, the Head First Design Patterns book used the coffee example to illustrate the Decorator pattern.

@ schambers

You could have saved yourself the effort of writing this (otherwise good) post and just linked straight to the freely available chapter 3 of DHDP:

oreilly.com/.../ch03.pdf

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems