Command design pattern

To finish with this chapter, we will see also the Command pattern--a tiny design pattern but still frequently used. You need a way to connect types that are really unrelated? So design a Command for them.

Description

The Command design pattern is quite similar to the Strategy design pattern but with key differences. While in the strategy pattern we focus on changing algorithms, in the Command pattern, we focus on the invocation of something or on the abstraction of some type.

A Command pattern is commonly seen as a container. You put something like the info for user interaction on a UI that could be click on login and pass it as a command. You don't need to have the complexity related to the click on login action in the command but simply the action itself.

An example for the organic world would be a box for a delivery company. We can put anything on it but, as a delivery company, we are interested in managing the box instead of its contents directly.

The command pattern will be used heavily when dealing with channels. With channels you can send any message through it but, if we need a response from the receiving side of the channel, a common approach is to create a command that has a second, response channel attached where we are listening.

Similarly, a good example would be a multi-player video game, where every stroke of each user can be sent as commands to the rest of the users through the network.

Objectives

When using the Command design pattern, we are trying to encapsulate some sort of action or information in a light package that must be processed somewhere else. It's similar to the Strategy pattern but, in fact, a Command could trigger a preconfigured Strategy somewhere else, so they are not the same. The following are the objectives for this design pattern:

  • Put some information into a box. Just the receiver will open the box and know its contents.
  • Delegate some action somewhere else.

The behavior is also explained in the following diagram:

Objectives

There we have a Command interface with a Get() interface{} method. We have a type A and a type B. The idea is that A and B implement the Command interface to return themselves as an interface{}. As now they implement Command, they can be used in a Command handler which doesn't care very much about the underlying type. Now A and B can travel through functions that handles commands or store Commands freely. But B handler can take an object from any Command handler to "unwrap" it and take its B content as well as A command handler with its A content.

We put the information in a box (the Command) and delegate what to do with it to the handlers of Commands.

A simple queue

Our first example is going to be pretty small. We will put some information into a Command implementer and we will have a queue. We will create many instances of a type implementing a Command pattern and we will pass them to a queue that will store the commands until three of them are in the queue, at which time it will process them.

Acceptance criteria

So the ideal acceptance criteria to understand well the implications of the Command should reflect somehow the creation of a box that can accept unrelated types and the execution of the Command itself:

  • We need a constructor of console printing commands. When using this constructor with a string, it will return a command that will print it. In this case, the handler is inside the command that acts as a box and as a handler.
  • We need a data structure that stores incoming commands in a queue and prints them once the queue reaches the length of three.

Implementation

This pattern is quite simple and we will write a few different examples so we'll implement the library directly to keep things light and short. The classical Command design pattern usually has a common type structure with an Execute method. We are also going to use this structure as it's quite flexible and simple:

type Command interface { 
  Execute() 
} 

This is generic enough to fill a lot of unrelated types! Think about it--we are going to create a type that prints to console when using the Execute() method but it could print a number or launch a rocket as well! The key here is to focus on invocations because the handlers are also in Command. So we need some type implementing this interface and printing to the console some sort of message:

type ConsoleOutput struct { 
  message string 
} 
 
func (c *ConsoleOutput) Execute() { 
  fmt.Println(c.message) 
} 

The ConsoleOutput type implements the Command interface and prints to the console the member called message.

As defined in the first acceptance criterion, we need a Command constructor that accepts a message string and returns the Command interface. It will have the signature func CreateCommand(s string) Command:

 func CreateCommand(s string) Command { 
   fmt.Println("Creating command") 
 
   return &ConsoleOutput{ 
         message: s, 
   } 
} 

For the command queue, we'll define a very simple type called CommandQueue to store in a queue any type implementing the Command interface:

type CommandQueue struct { 
  queue []Command 
} 
 
func (p *CommandQueue) AddCommand(c Command) { 
  p.queue = append(p.queue, c) 
 
  if len(p.queue) == 3 { 
    for _, command := range p.queue { 
      command.Execute() 
    } 
 
    p.queue = make([]Command, 3) 
  } 
} 

The CommandQueue type stores an array of the Commands interface. When the queue array reaches three items, it executes all the commands stored in the queue field. If it hasn't reached the required length yet, it just stores the command.

We will create five commands, enough to trigger the command queue mechanism, and add them to the queue. Each time a command is created, the message Creating command will be printed to the console. When we create the third command, the automatic command executor will be launched, printing the first three messages. We create and add two commands more, but because we haven't reached the third command again, they won't be printed and just the Creating command messages will be printed:

func main() { 
  queue := CommandQueue{} 
 
  queue.AddCommand(CreateCommand("First message")) 
  queue.AddCommand(CreateCommand("Second message")) 
  queue.AddCommand(CreateCommand("Third message")) 
 
  queue.AddCommand(CreateCommand("Fourth message")) 
  queue.AddCommand(CreateCommand("Fifth message")) 
} 

Let's run the main program. Our definition said that the commands are processed once every three messages and we will create a total of five messages. The first three messages must be printed but not the fourth and fifth because we didn't reach a sixth message to trigger the command processing:

$go run command.go
Creating command
Creating command
Creating command
First message
Second message
Third message
Creating command
Creating command

As you can see, the fourth and fifth messages aren't printed, as expected, but we know that the commands were created and stored on the array. They just weren't processed because the queue was waiting for one command more to trigger the processor.

More examples

The previous example shows how to use a Command handler that executes the content of the command. But a common way to use a Command pattern is to delegate the information, instead of the execution, to a different object.

For example, instead of printing to the console, we will create a command that extracts information:

type Command interface { 
  Info() string 
} 

In this case, our Command interface will have a method named Info that will retrieve some information from its implementor. We will create two implementations; one will return the time passed since the creation of the command to its execution:

type TimePassed struct { 
  start time.Time 
} 
 
func (t *TimePassed) Info() string { 
  return time.Since(t.start).String() 
} 

The time.Since function returns the time elapsed since the time stored in the provided parameter. We returned the string representation of the passed time by calling the String() method on the time.Time type. The second implementation of our new Command will return the message Hello World!:

type HelloMessage struct{} 
 
func (h HelloMessage) Info() string { 
  return "Hello world!" 
} 

And our main function will simply create an instance of each type, then waits for a second and print the info returned from each Command:

func main() { 
  var timeCommand Command 
  timeCommand = &TimePassed{time.Now()} 
 
  var helloCommand Command 
  helloCommand = &HelloMessage{} 
 
  time.Sleep(time.Second) 
   
  fmt.Println(timeCommand.Info()) 
  fmt.Println(helloCommand.Info()) 
} 

The time.Sleep function stops the execution of the current goroutine for the specified period (a second). So, to recall--the timeCommand variable stores the time when the program was started and its Info() method returns a string representation of the time that passed since we give a value to the type to the moment were we called the Info() method on it. The helloCommand variable returns the message Hello World! when we call its Info() method. Here we haven't implemented a Command handler again to keep things simple but we can consider the console as the handler because we can only print ASCII characters on it like the ones retrieved by the Info() method.

Let's run the main function:

go run command.go
1.000216755s
Hello world!

Here we are. In this case, we retrieve some information by using the Command pattern. One type stores time information while the other stores nothing and it simply returns the same simple string. Each time we run the main function will return a different elapsed time, so don't worry if the time doesn't match with the one in the example.

Chain of responsibility of commands

Do you remember the chain of responsibility design pattern? We were passing a string message between links to print its contents. But we could be using the previous Command to retrieve information for logging to the console. We'll mainly reuse the code that we have written already.

The Command interface will be from the type interface that returns a string from the previous example:

type Command interface { 
  Info() string 
} 

We will use the Command implementation of the TimePassed type too:

type TimePassed struct { 
  start time.Time 
} 
 
func (t *TimePassed) Info() string { 
  return time.Since(t.start).String() 
} 

Remember that this type returns the elapsed time from the object creation on its Info() string method. We also need the ChainLogger interface from the Chain of responsibility design pattern section of this chapter but, this time, it will pass Commands on its Next method instead of string:

type ChainLogger interface { 
  Next(Command) 
} 

We'll use just the same type for two links in the chain for simplicity. This link is very similar to the FirstLogger type from the chain of responsibility example, but this time it will append the message Elapsed time from creation: and it will wait 1 second before printing. We'll call it Logger instead of FirstLogger:

type Logger struct { 
  NextChain ChainLogger 
} 
 
func (f *Logger) Next(c Command) { 
  time.Sleep(time.Second) 
 
  fmt.Printf("Elapsed time from creation: %s
", c.Info()) 
 
  if f.NextChain != nil { 
    f.NextChain.Next(c) 
  } 
} 

Finally, we need a main function to execute the chain that takes Command pointers:

func main() { 
  second := new(Logger) 
  first := Logger{NextChain: second} 
 
  command := &TimePassed{start: time.Now()} 
 
  first.Next(command) 
} 

Line by line, we create a variable called second with a pointer to a Logger; this is going to be the second link in our chain. Then we create a variable called first, that will be the first link in the chain. The first link points to the second variable, the second link in the chain.

Then, we create an instance of TimePassed to use it as the Command type. The start time of this command is the execution time (the time.Now() method returns the time in the moment of the execution).

Finally, we pass the Command interface to the chain on the first.Next(command) statement. The output of this program is the following:

go run chain_command.go
Elapsed time from creation: 1.0003419s
Elapsed time from creation: 2.000682s

The resulting output is reflected in the following diagram: The command with the time field is pushed to the first link that knows how to execute Commands of any type. Then it passes the Command to the second link that also knows how to execute Commands:

This approach hides the complexity behind each Command execution from the Command handlers on each link. The functionality hidden behind a Command can be simple or incredibly complex but the idea here is to reuse the handler to manage many types of unrelated implementations.

Rounding-up the Command pattern up

Command is a very tiny design pattern; its functionality is quite easy to understand but it's widely used for its simplicity. It looks very similar to the Strategy pattern but remember that Strategy is about having many algorithms to achieve some specific task, but all of them achieve the same task. In the Command pattern, you have many tasks to execute, and not all of them need to be equal.

So, in short, the Command pattern is about execution encapsulation and delegation so that just the receiver or receivers trigger that execution.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.134.188