A simple yet powerful object-oriented design pattern.

Ah, design patterns. They bring simplicity, organization and scalability to any fitting situation. In fact, code that has no backing in design often leads to major headaches and spaghetti code down the road. To me, knowing a flexible list of design patterns distinguishes software developers from software engineers. They allow you to plan and scale for the future, because things are bound to change. And when they do, you had better be prepared!

So without further introduction, let’s get to one of my favorites — The Command Pattern.

**Attention! **This article assumes you have working knowledge of:

  • Object-Oriented Programming
  • UML Diagrams
  • GoLang

The Big Idea

The command pattern is intended for situations when you just don’t care about the plumbing. Actually, the concepts behind this pattern are often used in everyday life! Take a remote controller for a TV for example, do you know exactly how clicking the (+) button actually increases volume? Probably not, and you don’t need to!

The command pattern is all about encapsulation and abstraction. In the case of the remote controller, each button is ideally encapsulated in that each button should be able to work independently of each other. In terms of abstraction, this is the whole point that you don’t need to know the details of how exactly any button in the controller actually communicates with the TV via signals and code. You just want each button to be able to easily perform a task or action without having to think about the details.

This strategy applies to nearly every modern day object around us! Your phone, a microwave or the dashboard to your car all abstract and encapsulate away nasty implementation details and allow you, the commander, to focus on high level commands. This frees up your time and allows someone with zero knowledge in electrical engineering to make a phone call to someone hundreds of miles away. That’s powerful!

The UML Class Diagram

Understanding the Unified Modeling Language (UML) Class Diagram will allow us to formalize our understanding of the command pattern. Take this diagram graciously supplied from Wikipedia below.

Image for post

From Wikipedia

Starting from top left, the Caller class is our driver program (in this case our main Go package). This class can also be referenced as the Invoker, but it simply takes care of calling our commands.

The Caller/Invoker has an associative relationship with our Command interface, which requires each inheriting ConcreteCommand to implement the execute() function. Note how the ConcreteCommand also has a state property — going back to our remote control this could be the current volume level.

Next, each ConcreteCommand calls a Receiver class that performs the actual action. While the ConcreteCommand stores the state (say volume level of the TV), the receiver could be the logic that actually communicates with the TV in order to perform volume actions such as increase, decrease or mute. The Client class would be you, with the remote controller itself being the Caller.

Implementing The Command Pattern With Go

Go is a bit different than other languages that are capable of object-oriented programming. The primary difference is that there is no inheritance in Go as well as no classes. Rather, you can create structs that can compliment interfaces in order to set contracts and define behavior.

In this example, we will be create a program that simulates a television that can turn on/off as well as change volume. First let’s start up our new project.

$ cd ~/go/src
$ mkdir command-pattern
$ cd command-pattern

Now, command pattern works by abstracting away code logic. We will have structs that represent buttons all the way up to our tv. We first need two interfaces for a command and a device.

device.go

package main

type device interface {
    on()
    off()
    increaseVolume()
    decreaseVolume()
}

command.go

package main

type command interface {
    execute()
}

Simple enough so far. It’s very common in the command pattern to have each command implement an execute() function. Now, we need to create a tv that will implement the device interface in addition to specific commands to execute. Let’s create our specific commands first.

onCommand.go

package main

type onCommand struct {
    device device
}

func (c *onCommand) execute() {
    c.device.on()
}

#programming #design-patterns #golang #developer #go

The Command Pattern with Go
3.95 GEEK