Decorator Pattern in Go

Srinjoy Santra
4 min readAug 29, 2021

This is the third chapter of the “Head First Design Patterns” book. I have covered the Strategy and Observer patterns before.

The problem

We are told to design an ordering application at a coffee shop. It sells a variety of beverages like

  • House Blend
  • Dark Roast
  • Decaf
  • Espresso

Apart from these, the customer has the choice to have condiments (add-ons) like

  • Steamed milk
  • Soy
  • Mocha
  • Whipped milk
a collage of coffee and various condiments

Thought process

Approach 1

  • What a noob coder like me would do is make an abstraction of Beverage, and derive concrete implementations of House Blend, Dark Roast, and so forth.
  • The problem arises with the condiments, using the above approach we are spoiled with choices and our implementations become

House Blend with steamed milk and mocha

Dark Roast with whip and soy

  • Just imagine the number of possibilities,
    #(Beverage) X #(condiments) X #(other condiments or not)
    that is 4 * 4 * 4 = 64 ; that’s simply explosion of classes

Approach 2

  • We maintain the boolean properties of every condiment for the Beverage abstraction. If the customer insists on adding one of these the respective boolean will be set to truthy value.
  • We have getters and setters for each of those properties.
  • The number of implementations now is 4, and 1 abstraction.
  • This reduces our implementations significantly, but we see some issues.
  • If things like price and number of add-ons change, we will need to rewrite the implementations.
  • A new beverage like iced tea can’t be enjoyed with the whip. But it will have the setter and getter for the same.

Approach 3

  • Here we make use of the decorator pattern.
  • The idea here is to keep on adding things as the customer wishes.
  • Suppose the customer orders a “double mocha soy latte with the whip” with espresso.*
  • We create espresso first, then keep putting our condiments in any order. e.g. Mocha, Soy Latte, Mocha, Whip
  • The cost function is incremented at each step with the power of polymorphism.

* I am not sure how will that taste in real life.😅

UML Class Diagram

UML diagram of our coffee system design. It consists of beverage and condimentDecorator abstractions and their concrete implementations
UML for our cafe ordering system design

Takeaways

The book defines,

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

Decorators make our code openly extensible but closed for modification.

In simpler terms, we can add new condiments (decorators) without touching the code of existing beverages or condiments.

Language specifics

Go doesn’t use inheritance which saves us from some cognitive load.

We simply make an interface Beverager that is implemented by the structs of beverages or condiments.

package utilstype Beverager interface {
Cost() float32
GetDescription() string
}

The implementation for Whip, a condiment.

package utils// Whip : Condiment
type Whip struct {
beverage Beverager
description string
cost float32
}
// NewWhip : Constructor
func NewWhip(b Beverager) Beverager {
m := Whip{b, "Whip", 0.10}
return &m
}
func (w *Whip) Cost() float32 {
return w.beverage.Cost() + w.cost
}
func (w *Whip) GetDescription() string {
return w.beverage.GetDescription() + ", " + w.description
}

The implementation of a beverage like DarkRoast differ from condiments by the fact

  • it does NOT accept another beverage on its creation. This makes sense, we should not mix DarkRoast with Espresso!
Decorator Pattern

One thing to note in the decorator patterns is that the order does not matter while adding condiments. In the above diagram, we could have wrapped the DarkRoast with Mocha followed by Whip.

Output

Inside func main()

The above code prints

Espresso = ₹ 1.99
Dark Roast, Mocha, Mocha, Whip = ₹ 1.4900001
House Blend, Soy, Mocha, Whip = ₹ 1.34

Wow, that’s cheap coffee! In reality, it costs a lot more. Please feel free to buy me some real coffee!!

View all the code in my Github repository.

Do you see a mistake in there? Mention in the comments.

Did you like it? Show your support through claps 👏.

I’m Srinjoy Santra, currently an SDE-1 at BookMyShow. You can connect with me on LinkedIn, visit my Github account, or follow me on Twitter.

--

--