DecoratorPattern

Type of the pattern:

The Decorator design pattern is a structural design patterns (design pattern that ease the design by identifying a simple way to realize relationships between entities.)

Problem it solves:

When you want to extend (not override) existing behavior and want a design which is resilient to change and flexible enough to add new functionality then decorator pattern is the way to go.

The Decorator Pattern attaches additional responsibility to the object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

 

Example:

Suppose a coffee house has designed their system to have a four different beverages each of which has a different description and a price. Existing design is as below

DecoratorPattern

Now if the coffee shop wants to extend the business and want to add condiments: mocha, steamed milk, whipped milk etc. each of which will add some cost to the existing beverage cost then what can be the possible system design approaches?

 

  1. We can come up with all type combinations for each of the beverage type and a condiment. For example, Expresso will be replaced by it’s variants EspressoWithSoy, EspressoWithSteamedMilk, EspressoWithMocha, EspressoWithWhip, EspressoWithSteamedMilkAndMocha ……

Roughly there will be 36 classes which all will extend Beverage abstract class. Obviously this is like a class explosion and it will get bigger and bigger with added beverages and condiments. More classes mean more maintenance. This is definitely not the way to go.

  1. Move all the condiments instances to abstract Beverage class with a flag for each which indicates whether beverage has the condiment or not. This way we can have all kind of condiment combinations for a beverage without having multiple classes. There are 2 major issues with this design though:
    • If a new beverage is added like Tea, then it will inherit all the condiments though it is not supposed to have them.
    • With every new condiment added we have to change Beverage superclass code for cost calculation. This violates OCP (Open Closed principle). Basically Beverage class has many reasons to change which also points out that it violates SRP (Single Responsibility Principle)

Now let’s see how we can solve this with Decorator Design Pattern

DecoratorPattern1

public abstract Class Beverage {

String description = “Unknown Beverage”;

public String getDescription(){

return description;

}

public abstract double cost();

}

 

public abstract Class CondimentDecorator extends Beverage {

public abstract String getDescription();

}

public Class Espresso extends Beverage {

public Espresso (){

description = “Espresso”;

}

Public double cost(){

Return .89;

}

}

Public class Mocha extends CondimentDecorator {

Beverage beverage;

public  Mocha(Beverage beverage){

this.beverage = beverage;

}

public String getDescription(){

Return beverage.getDescription() + “, Mocha”;

}

public double cost(){

Return .20 + beverage.cost();

}

 

}

 

public class Whip extends CondimentDecorator {

Beverage beverage;

public  Whip(Beverage beverage){

this.beverage = beverage;

}

public String getDescription(){

Return beverage.getDescription() + “, Whip”;

}

public double cost(){

Return .6 + beverage.cost();

}

 

}

 

Here is a Test class :

Public class CoffeeShop {

Beverage beverage = new Espresso();

beverage = new Mocha(beverage) //wrapped in single Mocha

beverage = new Mocha(beverage) //wrapped in double Mocha

beverage = new Whip(beverage) //wrapped in whip

s.o.p(beverage.cost());

}

Output for this will be 1.89

 

 

 

Decorator pattern

Post navigation


Leave a Reply

Your email address will not be published. Required fields are marked *