This is the 9th day of my participation in the August More Text Challenge

Command mode is not something that many of you might use, but it’s interesting. In command mode, operations and data can be packaged into objects, facilitating the system to manage and maintain commands.

UML class diagrams location: www.processon.com/view/link/6…

This article is linked to: github.com/shidawuhen/…

Definition 1.

1.1 Command Mode

Command pattern: Encapsulates a request as an object, allowing you to parameterize clients with different requests; Queue or log requests, and support undoable operations.

UML:

1.2 analysis

The above definitions and UML are complex and may be difficult for you to understand.

First we need to understand what a command is. Commands include instructions and data. Instructions are actions, and data affects instructions. If 3 meters forward, forward is an instruction, 3 meters is data.

Then let’s look at what each class means.

Command and ConcreteCommand are commands with Excute functions that represent actions to be performed.

ConcreteCommand calls Excute(), and finally calls the Action of the Receiver. This means that the ConcreteCommand is just a container, and the real operation logic is in the Receiver.

The Invoker contains all the commands that control when the Command executes Excute().

Now let’s simplify UML, leaving out Invoker and Receiver, and see if it’s easy to understand.

With this concise version of UML, let’s look at why the command pattern is used.

Commands include instructions and data. Instructions actually correspond to operations, and operations correspond to functions in code.

In fact, the command mode is to encapsulate the function as an object, the system can perform various operations on the object, such as queuing execution, logging, undo and so on.

Why wrap functions as objects? C, C++, and Go support function Pointers, but not all languages do, and command mode comes into play. And even if the language supports function Pointers, there is still a problem with how to store the data part of a command.

Therefore, the Command mode is to package the request into a Command object, store it, and the system will process it according to the actual demand.

2. Application scenarios

You may feel that the command mode is the same as MQ or factory mode, but it is different in detail:

  • MQ contains only data, not behavior, and command mode contains both

  • Factory mode requires real-time execution, but command mode can be stored and executed later

Command mode I’ve never used before. Beauty in Design Patterns describes a common architecture for game development: client requests are stored by a server, which has a separate thread to process them. So let’s write the code according to this scenario.

3. Code implementation

package main

import "fmt"

/** * @author: Jason Pang * @description: Command interface */
type Command interface {
   Execute()
}

/** * @author: Jason Pang * @description: Move command */
type MoveCommand struct {
   x, y int64
}

/** * @author: Jason Pang * @description: How to move * @receiver m */
func (m *MoveCommand) Execute(a) {
   fmt.Printf("Move %d to the right, move %d \n up", m.x, m.y)
}

/** * @author: Jason Pang * @description: Attack command */
type AttackCommand struct {
   skill string
}

/** * @author: Jason Pang * @description: How to attack @receiver a */
func (a *AttackCommand) Execute(a) {
   fmt.Printf("Use skill %s\n", a.skill)
}

/** * @author: Jason Pang * @description: Record Command * @param action * @return Command */
func AddCommand(action string) Command {
   if action == "attack" {
      return &AttackCommand{
         skill: "Savage Collision.",}}else { // The default is move
      return &MoveCommand{
         x: 10,
         y: 20,}}}func main(a) {
   // Record the command
   lc := make([]Command, 0)
   lc = append(lc, AddCommand("attack"))
   lc = append(lc, AddCommand("move"))
   lc = append(lc, AddCommand("move"))
   lc = append(lc, AddCommand("attack"))

   // Execute the command
   for _, c := range lc {
      c.Execute()
   }
}

Copy the code

Output:

➜ myproject go run main.go

Use the ability to brutalize

We went 10 to the right, we went 20 up

We went 10 to the right, we went 20 up

Use the ability to brutalize

From the above code, you should be able to understand the command pattern. It can be seen that different commands are generated for different requests, which contain corresponding data and operations. This is also what the schema definition says about “queuing or logging requests, and supporting undoable actions”.

conclusion

Design patterns are designed to solve real-world problems, and we need to tie them to concrete scenarios. When solving problems, it doesn’t matter whether standard design patterns are used or not. Patterns are only means, and means need to serve the purpose.

The last

If you like my article, you can follow my public account (Programmer Malatang)

My personal blog is shidawuhen.github. IO /

Review of previous articles:

  1. Design patterns

  2. recruitment

  3. thinking

  4. storage

  5. The algorithm series

  6. Reading notes

  7. Small tools

  8. architecture

  9. network

  10. The Go