The Decorator Pattern

Jon
4 min readOct 31, 2020

The decorator pattern is one of the 23 design patterns described by the Gang of Four in their well-known book, Design Patterns: Elements of Reusable Object-Oriented Software. The decorator pattern allows the user to add new functionality to an existing object without altering its structure. Not too sure what that means? Let’s start with an example!

Suppose you are the manager of the new bubble tea chain down the street, 9123 café. Your stall serves many different drinks to satisfy your customers’ tea cravings, such as Milk Tea, Brown Sugar Milk Tea, Fresh Fruit Tea and so on. You decide to define an abstract class Beverage that contains information about the item, such as the drink’s cost. Each new drink will subclass the Beverage abstract class and implement its own getCost() function to return the cost of the beverage item.

Class Diagram of a Beverage item.

To ride onto the bubble tea craze, your stall allows customers to customize their drink by adding toppings such as Pearls, Aloe Vera, Ice Cream, Grass Jelly and more. Each topping requires changes to the cost of the item, so you start to build your ordering system like this:

Class Diagram of your initial attempt of the Ordering System (!?)

This first attempt looks like a recipe for disaster. What if there was that new taro topping that you want to add to the menu? What happens if you decide that the prices of pearl toppings should go up? This seems to violate the open-close principle, which states that classes should be open for extension, but closed for modification. We want our design to be flexible enough to incorporate new changes, such as additional toppings, with minimal changes to the existing code.

Introducing the Decorator pattern to the rescue! The decorator pattern allows you to add extra functionality on top of a base object, which sounds like exactly what we need in this case. We could start with a base MilkTea object and then add on “decorators” that wrap the base object, such as a Pearls object, an IceCream object and so on. When we are satisfied with our final order, we take that order and call getCost() on it, and we can use delegation to calculate the order’s final cost with the decorators placed on it!

Sequence of getCost() calls to calculate the final beverage cost with a Decorator pattern

As we can see, the decorator first adds its own behaviour (in this example, the decorator adds the topping cost) and then delegates to the object it decorates to perform the rest of the intended functionality. Let us take a look at the Class Diagram representation of a Decorator pattern, and how we would implement this concretely:

Class Diagram of a Decorator Pattern
Class Diagram of your Ordering System using a Decorator Pattern

You may be wondering how we could implement this in actual code. Well, here is how we could implement a Decorator pattern in Java (using our example above). First, we start off with the implementations of the base class and the decorator.

Concrete Implementation of the base Beverage class and the decorator BeverageToppingDecorator

Next, we have two concrete implementations of the Beverage class.

Two concrete implementations of the Beverage class

Now here’s the magic of the pattern, a concrete implementation of a BeverageToppingDecorator class.

A concrete implementation of a BeverageToppingDecorator class

As seen in the code snippet above, the calls to getDescription() and getCost() delegates the work to the wrapped object originalBeverage and extends its functionality, such as adding its own topping price and modifying the description accordingly.

So now, we have an implementation of your ordering system that is easily extensible to support further customization such as new toppings and new drinks. Your bubble tea store is on its way to be the next new craze!

--

--