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!