Decorator Pattern

What is Decorator Pattern?

Decorator pattern attaches additional responsibilities to an object dynamically (at runtime). It provides flexible alternative to subclassing for extending functionality. 

It involves a set of Decorator classes that are used to wrap concrete components. Decorator classes mirror the object they wrap and change the behavior of concrete components by adding new functionalities.

Let’s use an example to understand this pattern –

We have our Pizza delivery service, we offer basic pizza with different types of bases and varieties of toppings like veggies, protein, extra cheese etc. Each different topping has it’s own price which adds up to the final cost. 

Say we implement this using inheritance, we would have our main object Pizza with some functionality and then we will have separate classes for different pizza on the menu, example one for cheese pizza, veggie delight pizza, etc.

 

Pizza object

The main drawbacks here would be that

  1. if any other topping is added, we will have to go an update Pizza’s cost method,
  2. Add it as variable with it’s accessors to the Pizza class
  3. If cost of any topping changes/discounts come, we would have to go and change it in Pizza class.
  4. All the different pizza types would not need all the toppings, example cheese pizza would not need veggies/protein, etc.

Let’s see how we can have an extensible solution using Decorator pattern – 

We will have our main Pizza object and our Toppings decorator object. CheesePizza is our Concrete component example. We have our ToppingsDecorator which is extended by different toppings that we add. We can see the following advantages –

  1. if you want to add a discount on the pizza, you can just create another decorator Discount on the pizza object.
  2. If prize of any topping changes, we just need to go to that concrete decorator and update the cost.

 

Pizza object using Decorator Pattern

Open-Closed Design Principle and Decorator Pattern

Open-Closed principle states that classes should be open for extension and closed for modification. If we find that our existing code needs new logic, example new behavior like adding discount, decorator pattern allows us to add that without modifying the existing object. 

Drawbacks

  • It could result in lot of small decorator objects, increasing number of objects and complexity

Real World Examples

  • Java I/O package classes 
  • Java Streams API