Coffee and the Decorator

Learn
4 min readFeb 28, 2020

--

Coffee is at it’s minimal coffee powder dissolved in water. Water without the powder or vice-versa would not qualify as coffee. Those are the mandatory ingredients.

If I consider my office coffee, sometimes I just have the elementary coffee.
At other times, I have added one or more of the following — sugar, dairy milk, almond milk, chocolate powder, cardamom, soya milk, vanilla powder, salt, hazelnut creamer, vanilla creamer. That is ten ingredients, which amounts to two raised to ten combinations — with the reasoning that for each ingredient you either choose it or you don’t, and then you do the same with the next ingredient and so on.

Now, say you want to represent the coffee consumption in the organization. You can have a class with the ten ingredients. For elementary coffee, the data members for these ten ingredients would not be used at all. There can have been say a hundred ingredients. Clearly, you would not want the Coffee class to carry all the hundred ingredients every time, especially when you consider the elementary coffee.

That is where the Decorator pattern steps in and gives you one decorator class per ingredient. That would mean there are hundred Decorator classes for the hundred Ingredients. The huge class with all the hundred ingredients would have been just one class. However, say in a day, the organization consumes ten thousand instances of coffee, there would have been ten thousand instances of the huge coffee class, which is fine, but each of those instances would have carried the hundred ingredient data members while on average, a coffee might have had just one or two ingredients in it. That is where having decorators per ingredient lets you represent just what is actually used.

To reiterate, if all the coffee instances are being represented using the big coffee class, then the memory footprint would be proportional to the maximal coffee that is possible, where as with decorators, the memory footprint would be proportional to the actual amounts of ingredients that were used in the coffees.

Coffee represents the component, the SugarDecorator is the decorator for the component coffee. Also, new SugarDecorator(coffee) is still coffee — it is coffee into which you have stirred in sugar. Similarly, new CreamerDecorator(coffee) is still coffee — it is coffee with creamer stirred in.

That means you can decorate coffee that is decorated with ingredient one, with another ingredient.

new CreamerDecorator(new SugarDecorator(coffee))

is coffee with creamer and sugar stirred in.And so on, for all the other decorators as well — ChocolateDecorator, CinnamonDecorator, AlmondMilkDecorator, and so on.

Decorator and Component

Decorator implements the Component’s interface. This is done so that the client of the component can just as well interact with the decorator as it would have interacted with the component.

Transparency

Why is it a big deal that the decorator have the same interface as the component from the client’s perspective?
The client just wanted to have coffee, and then he just considered decorating it. Now, if he has to start drinking it with a straw instead of from the cup, he might give up on using the decorator. Essentially, it is less hassle for the clients when the decorator implements the same interface as the component. The additional “cost” of the usage of the decorator is minimized.

The decorator is transparent to the client. The client doesn’t see it. He just sees the coffee.

Forwarding

The decorator does it’s decoration stuff and then forwards the control to the component. This forwarding can be done before/after.

Recursive nesting of decorators

Telescoping construction pattern as below allows quite some decorative power to the client.

dOne(dTwo(dThree(dFour(dFive(component

Skin and Gut

Decorators are about customization of the component, adding additional functionality to the component. It is about changes, but without affecting the guts. It is decorated, but it is still coffee.

Strategy pattern, on the other hand, is about changing the fundamentals of the component’s character. The core algorithm of the class itself is being changed when the strategy pattern is applied.

Static inheritance and decorators

We had spoken only about having a huge class with hundred ingredients to compete with the hundred decorator classes. Another alternative is to have an inheritance hierarchy — Coffee, CoffeeWithSugar, CoffeeWithSugarAndCreamer etc. Just from the way the classes are being named, we get the sense that the static inheritance approach would not scale.

Decorators are way more flexible as each decorator is focused on one ingredient each and the decorator eco-system lets each decorator play it’s part when needed.

The down side to decorators is the big number of small classes that are being added to the system.

--

--

Learn
Learn

Written by Learn

On a continuing learning journey..

No responses yet