Design Patterns : Decorator Pattern

While Inheritance/Sub Classing seems to be most natural way of extending functionality, it might not be always the best option. Especially when you want to avoid subclassing as it might result in too many classes. Consider the following scenario.

Your nearest Dominos has many varieties of Pizzas. On top of it, you could decorate each of those pizzas with extra toppings and choose from a variety of crusts. If we were go with the conventional sub classing approach, we could end up with a lot of sub classes as seen below.
Pizza

For each combination of Pizza and topping, we would need to create a separate sub class. Add to it, options available for crust, and the sub classes could go up higher. This is here Decorator Pattern comes into picture. Decorator Pattern allows us to add functionality/feature to existing classes without having to go through the pain of too many sub classes. Of course, Decorator Pattern too does make use of inheritance, but in a more efficient way.

 

Let’s go ahead and Implement Pizza Classes using Decorator Pattern, beginning with the Contract Interface and choice of base Pizzas.
public interface IPizza
{
  string Description { get; }
  int CalculatePrice();
}

public class MexicanGreenWavePizza : IPizza
{
  public string Description => "Mexican Green Wave Pizza";
  public int CalculatePrice() => 105;
}

public class MargheritaPizza : IPizza
{
  public string Description => "Margherita Pizza";
  public int CalculatePrice() => 100;
}

public class ChickenTikkaPizza : IPizza
{
  public string Description => "Chicken Tikka Pizza";
  public int CalculatePrice() => 115;
}

We will now add our decorators.

class CheeseCrust : IPizza
{
  private IPizza _PizzaInstance;
  public CheeseCrust(IPizza pizza) => _PizzaInstance = pizza;
  public string Description => $"{_PizzaInstance.Description} With Cheese  Crust";
  public int CalculatePrice() => _PizzaInstance.CalculatePrice() + 7;
}

public class ExtraGoldenCorn : IPizza
{
  private IPizza _PizzaInstance;
  public ExtraGoldenCorn(IPizza pizza) => _PizzaInstance = pizza;

  public string Description => $"{_PizzaInstance.Description} with Extra  Golden Corn";
  public int CalculatePrice() => _PizzaInstance.CalculatePrice() + 5;
}

As you might have already noticed, the decorator classes not just inherit from IPizza interface, but it also have an instance of Pizza with it, injected using Dependency Injection.  This allows us to use the decorators with any combination of base classes (and with each other) without having to write too many sub classes as we had observed in the image above. The client can now use any combination of Pizza’s with their decorators.

IPizza vegPizza = new MargheritaPizza();
var vegPizzacheezeCrust = new CheeseCrust(vegPizza); // Added  Decorator

IPizza nonVegPizza = new ChickenTikkaPizza();
var chickenPizzacheezeCrust = new CheeseCrust(nonVegPizza); // Added  Decorator
var chickenPizzacheezeCrustAndExtraGoldenCoren = new  ExtraGoldenCorn(chickenPizzacheezeCrust); // Added Decorator

Console.WriteLine($"{vegPizzacheezeCrust.Description}, Price  :  {vegPizzacheezeCrust.CalculatePrice()}");
Console.WriteLine($"{chickenPizzacheezeCrustAndExtraGoldenCoren.Description},  Price  : {chickenPizzacheezeCrustAndExtraGoldenCoren.CalculatePrice()}");

Output

Margherita Pizza With Cheese Crust, Price  : 107
Chicken Tikka Pizza With Cheese Crust with Extra Golden Corn, Price  : 127<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

The complete reference source code for the example can be found in my Github. To learn more on Design Patterns, refer here.

Advertisement

One thought on “Design Patterns : Decorator Pattern

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s