The Decorator Design Pattern

The Decorator design pattern is a structural design pattern that allows you to add functionalities to an object at runtime.

Why Decorator ?

  • If you need to attach additional responsibilities to an object dynamically.
  • When sub-classing becomes impractical.
  • You have a large number of possible functionalities and you need independent ways to add them to object.

Participants

  • Component
  • Concrete Component
  • Decorator
  • Concrete Decorator

Problems with Decorator

  • Have to manage more objects, so there is an increased chance of coding errors

this is what i overheard at the Pizza store down the street…

Customer1: Get me a Veggie Pizza with lots of low-fat cheese, and don’t forget to top it with some spinach…

Customer2: For me, a Cheese pizza decorated with broccoli and red-hot sauce…and also double liquid mozzarella cheese…

Suppose the owner of this pizza shop approaches you to write an application for his business, after all you are an awesome OO Developer. Think….what classes you need to write ???

If you say, one for each kind of pizza, i would remind you of a large list of toppings the pizza shop offers…after all whats a pizza without  toppings?? :p and also a customer can ask for double toppings …say double cheese toppings and single sauce…then in that case would you write

VeggiePizzaWithDoubleMozzarellaCheeseAndSauce

VeggiePizzaWithLowfatCheeseAndSpinach

CheesePizzaWithMozzarellaCheeseAndSauce and so on……

Its like writing a class for every permutation & combination of available pizza types and toppings.

Think….Think….Think….

In such cases, the decorator design pattern is what you need

Component – Pizza

public abstract class Pizza {

    String description;
    abstract String getDescription();
    abstract int getCost();
    //other useful methods
}

Concrete Component – CheesePizza and VeggiePizza

public class CheesePizza extends Pizza {

    public CheesePizza() {
        description = "Cheese Pizza";
    }

    @Override
    String getDescription() {
        return description;
    }

    @Override
    int getCost() {
        return 95;
    }
}

 

public class VeggiePizza extends Pizza {

    public VeggiePizza() {
        description = "Veggie Pizza";
    }

    @Override
    String getDescription() {
        return description;
    }

    @Override
    int getCost() {
        return 80;
    }
}

Meet the Decorator

public abstract class PizzaTopping extends Pizza {

    @Override
    public abstract String getDescription();
}

The decorator extends the abstract Component – Pizza

You might be thinking…. isn’t decorator pattern used when we need to enhance an object’s functionality at runtime  (using composition) rather than at compile-time (using inheritance) ???

The decorators should have the same type as the objects they are going to decorate. So here we’re using inheritance to achieve the type matching, not to get behavior.

and then the delicious Concrete Decorators…

All Concrete Decorators extend the abstract Decorator – PizzaTopping

I’ve shown only 3 of them – LowFatCheesePepperSauce and Broccoli

public class LowFatCheese extends PizzaTopping {

    Pizza pizza;

    public LowFatCheese(Pizza pizza) {
        this.pizza = pizza;
    }

    @Override
    public String getDescription() {
        return pizza.getDescription() + " + Low-fat Cheese";
    }

    @Override
    public int getCost() {
        return 30 + pizza.getCost();
    }
}

PepperSauce

public class PepperSauce extends PizzaTopping {

    Pizza pizza;

    public PepperSauce(Pizza pizza) {
        this.pizza = pizza;
    }

    @Override
    public String getDescription() {
        return pizza.getDescription() + " + Pepper Sauce";
    }

    @Override
    public int getCost() {
        return 20 + pizza.getCost();
    }
}

Broccoli

public class Broccoli extends PizzaTopping {

    Pizza pizza;

    public Broccoli(Pizza pizza) {
        this.pizza = pizza;
    }

    @Override
    public String getDescription() {
        return pizza.getDescription() + " + Broccoli";
    }

    @Override
    public int getCost() {
        return 20 + pizza.getCost();
    }
}

We compose a decorator with a component to add new behavior. Yes you are correct, it is because we are using object composition we get a whole lot more flexibility to top a pizza with any topping any number of times.

Its time to order some pizzas…

public class DecoratorTest {

    public static void main(String ar[]) {

        //A Veggie Pizza without any Toppings
        Pizza pizza1 = new VeggiePizza();
        System.out.println(pizza1.getDescription() + " Rs. " + pizza1.getCost());

        //A Veggie Pizza with Low-fat Cheese and Broccoli
        Pizza pizza2 = new LowFatCheese(new Broccoli(new VeggiePizza()));
        System.out.println(pizza2.getDescription() + " Rs. " + pizza2.getCost());

        //A Cheese Pizza with Spinach and double Moozzarella cheese
        Pizza pizza3 = new Spinach(new MozzarellaCheese(new MozzarellaCheese(new CheesePizza())));
        System.out.println(pizza3.getDescription() + " Rs. " + pizza3.getCost());

    }
}

Did you observe the chain that we created ?, linking one topping to other and finally with a plain pizza. you would be spared if you call this way of creating objects as Chaining. It is also called as Wrapping, as we wrap one object with another.

and finally the output

Veggie Pizza Rs. 80
Veggie Pizza + Broccoli + Low-fat Cheese Rs. 130
Cheese Pizza + Mozzarella Cheese + Mozzarella Cheese + Spinach Rs. 165

Happy Decorating 🙂

Leave a comment