Introduction
I am back today with a new old topic: Design Patterns! So this started with an article posted by a good friend of mine about his way of implementing the factory pattern.
Although there is nothing to approach about his way, something kept itching me to write a second article about another design pattern that might fit in this situation as well.
Let’s start by reviewing the task:
The Straw hats pirates (the pirate crew in the one piece anime) contacted my company to write a software to automate pizza preparation. Sanji explained that in order to prepare pizza, we need to:
- Prepare the pizza dough
- Prepare the sauce
- Add pizza sauce and pizza ingredients according to each person’s desires
- Put the pizza in the oven
In order to complete the task, my friend wrote a Pizza maker base class where inherited classes redefine the AddIngredient
method to suit each person’s choices.

For example, if the person is Nami, then ingredients will be cheese and olives. To add his own touch, my friend added a configuration section to make class adding totally on the fly. There is no doubt that the solution is flexible and neat but what happens when more people join in the team? Or when current crew feels like tasting something new? Are we going to create sub classes for each possibility like this:

It’s sure not a good solution because with 3 ingredients (Olive, cheese and meat), we can have up to 7 different combinations (result = n! / [(n-k)! k!] Where n is total number of ingredients and k is the number of the picked ingredients), Imagine what will happen with 4 or 5 ingredients => explosion in number of sub classes.
What should we do then? It’s time to introduce the Decorator Pattern!
The decorator pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Don’t worry if you don’t understand this, I myself didn’t when I first read it but this example will help clear things for us.

Component: is the father of all, can exist on his own or equipped with decorators.
ConcreteComponent: son of component, can do more cool stuff than his old father.
Decorator: sort of the mother of all decorators, it teaches them the ABCs of life without precising how to act.
ConcreteDecorator: the real deal where decorator operations are defined.
Let’s put this in action and see what we get:

Explanation
Our main goal is to treat all pizza objects the same (this is why everything inherits from Pizza
class) and provide a mecanism to decorate our objects in a way that makes them different from one another.
The Pizza
here is your component, it’s the base class of the object you want to decorate.
public class Pizza
{
public void PreparePizza()
{
}
private void AddSauce()
{
}
public virtual void MakeDough()
{
}
private void PutInOven()
{
}
private void PrepareSauce()
{
}
public virtual string GetIngredients()
{
return "Pizza with ";
}
}
Three classes derive directly from Pizza
: the first two (CrustyDoughPizza
and ThickDoughPizza
) are considered ConcreteComponents
since they extend Pizza
’s behavior (Exp: creates a different more delicious dough).
public class ThickDoughPizza : Pizza
{
public override void MakeDough()
{
}
public override string GetIngredients()
{
return "Thick Dough Pizza with ";
}
}
public class CrustyDoughPizza : Pizza
{
public override void MakeDough()
{
}
public override string GetIngredients()
{
return "Crusty Dough Pizza with ";
}
}
The last third sub class is PizzaIngredient
which is the base class of any pizza ingredient since it defines what is expected from an ingredient. In this case, it forces every ingredient to override the behaviour of GetIngredients
method of the Pizza
class in order to have its own special implementation. Notice also the existence of a pizza field (MyPizza
), its use will be covered later.
public abstract class PizzaIngredient : Pizza
{
public Pizza MyPizza {get; set;}
public override abstract string GetIngredients();
}
Finally, by implementing PizzaIngredient
methods, subclasses share the same methods but with custom functionalities therefore they can decorate Pizza
objects rendering equally different but without compromising their origin. Hold on a sec, how can they decorate Pizza
objects?
public class Cheese : PizzaIngredient
{
public Cheese(Pizza pizza)
{
MyPizza = pizza;
}
public override string GetIngredients()
{
return MyPizza.GetIngredients() + " Cheese";
}
}
public class Olive : PizzaIngredient
{
public Olive(Pizza pizza)
{
MyPizza = pizza;
}
public override string GetIngredients()
{
return MyPizza.GetIngredients() + " Olive";
}
}
public class Meat : PizzaIngredient
{
public Meat(Pizza pizza)
{
MyPizza = pizza;
}
public override string GetIngredients()
{
return MyPizza.GetIngredients() + " Meat";
}
}
Excellent question, each ingredient must have a constructor which takes a Pizza
argument. Decoration occurs when this argument is assigned to the MyPizza
property. If we need to decorate an already decorated object, all we need to do is pass in the decorated object as an argument (it's pizza after all) to the custom constructor of the decorator.
Let’s try to make a CrustyDoughPizza
with olive only:
CrustyDoughPizza myPizza = new CrustyDoughPizza();
Olive olivePizza = new Olive(myPizza);
var pizzaIngredients = olivePizza.GetIngredients();
How? One Word: Recurrence!
When we call GetIngredients
of Olive
, it will bounce to call GetIngredients
of CrustyPizza
before it replies back to us just like in the schema below.

Let’s now do a more complicated thing: a ThickDough
Cheese and Meat Pizza:
ThickDoughPizza myPizza = new ThickDoughPizza();
Meat pizzaWithMeat = new Meat(myPizza);
Cheese pizzaWithCheese = new Cheese(pizzaWithMeat);
var pizzaIngredients = pizzaWithCheese.GetIngredients();
I believe this is a good solution for a situation when we don’t have control over the choices of the client. The decorator pattern makes components and decorators behave the same way abstracting differences and eliminating useless conditional tests but you may want to be careful about how you want to adjust your implementation to your case through interfaces and abstract classes.