Strategy Pattern in Golang

Srinjoy Santra
4 min readFeb 20, 2021

--

Usually I find technical books very dry, but Head First Design Patterns was awash with funny anecdotes and eye-grabbing illustrations. It felt a good place to start learning design patterns though it may miss out on more intricate details. The code examples are in Java. I recently started learning Go and chose it to implement the strategy pattern.

Strategy Pattern

According to the book,

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Okay, that did not make much sense to me at first too. Let’s try to understand through the problem statement.

The problem statement

We are told to design a duck pond simulation where different species of ducks exist. They can have a variety of swimming styles, flying abilities and sounds.

Requirements keep on changing, but finally we have four types of ducks.

Four types of ducks!
  1. Mallard Duck:
  • Which is actually a kind of duck species.
  • It can fly.
  • It makes a quack sound.
  • It can float.

2. Redhead Duck:

  • Which is actually a kind of duck species.
  • It can fly.
  • It makes a quack sound.
  • It can float.

3. Rubber Duck:

  • Which is the kind of yellow rubber ducks we see in bathrooms!
  • It can NOT fly.
  • It makes a squeaking sound.
  • It can float.

4. Decoy Duck:

  • Which is the kind of wooden ducks showcased in your living rooms!
  • It can NOT fly.
  • It does NOT make any sound.
  • It can float.

Thought process

  • Our initial instinct is to make a class of Duck, which has the functions of fly, quack and swim.
  • Subclasses Mallard, Redhead, Rubberand Decoycan inherit the behaviours from Duck.
  • Rubber and Decoy will override the default fly and quack behaviours to do nothing. Which do not make much sense!
  • We change our approach to have Flyable and Quackable interfaces, which the individual subclasses may choose to use.
  • We can implement the behaviours, inside the respective classes, but that will lead to repetition. e.g. Both Rubber and Decoy ducks cannot fly. So, it is better to have a FlyWithWings class (for Mallard and Redhead) and FlyNoWay(for Rubber and Decoy) implement the Flyable interface.
  • Similarly, for Quackable interface we make classes based on types of sound made.
  • The final solution (shown below) can appear over-engineered for the simple use case but helps a lot in flexibility for more bigger applications.
  • To enable switching behaviours at run-time (dynamic dispatch), we add two setters setQuacker and setFlyer to the Duck class.
  • In the book, a new type of Duck is introduced whose flight is powered by a rocket.
  • I took creative liberty, to instead have Donald Duck, the cartoon character. As far as I remember he can’t fly despite having 2 wings (hands?). He mutters “Aw, phooey!”, in his quintessential tone.
Photo by Kin Li on Unsplash

UML Class Diagram

class diagram as shown in ‘Head First Design Pattern’ book
Class Diagram showing the use of strategy pattern (Source: Head First Design Patterns)

FlyBehaviour has been renamed to Flyer; likewise for QuackBehaviour.

Language specifics

Golang is not a pure object-oriented programming language. However, we can use the language constructs to implement strategy pattern and can benefit from it.

There is no concept of class. A struct can have fields (data members). Interface can declare functions which need to be implemented by the struct.

Setter is NOT considered an idiomatic Go approach. In the code, I have shown use of both a setter and a direct member access of a public field.

The Code

Dynamic Dispatch in Golang

The output of the following code is

I'm a duck.
utils.Duck{flyer:utils.Flyer(nil), Quacker:utils.Quacker(nil)}
utils.Duck{flyer:utils.FlyNoWay{NoOfWings:0}, Quacker:utils.MuteQuack{}}
<< Silence >>
utils.Duck{flyer:utils.FlyNoWay{NoOfWings:2}, Quacker:utils.Speak{Speech:"Aw, phooey!"}}
Aw, phooey!

The complete code can be found in my Github repository.

Takeaways

This pattern “Favours composition over inheritance” which is in alignment with Golang’s philosophy (inheritance is not supported).

Some interesting design principles which came up

Identify the aspects of your application that vary and separate them from what stays the same.

Program to an interface, not an implementation.

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 a SDE-1 at BookMyShow. You can connect with me on LinkedIn, visit my Github account, or follow me on Twitter.

--

--

Srinjoy Santra
Srinjoy Santra

Written by Srinjoy Santra

Coder, Amateur Musician, Blogger

No responses yet