Go设计模式(26)-命令模式

简介: 命令模式很多同学可能不会用到,但这个模式还是蛮有意思的。命令模式能够将操作和数据打包成对象,便于系统对命令进行管理、维护。

命令模式很多同学可能不会用到,但这个模式还是蛮有意思的。命令模式能够将操作和数据打包成对象,便于系统对命令进行管理、维护。

UML类图位置:https://www.processon.com/view/link/60d29bf3e401fd49502afd25

本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/26command.go

1.定义

1.1命令模式

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

UML:

图片

1.2分析

上面的定义和UML比较复杂,大家可能比较难理解。

首先我们需要明白什么是命令。命令包括指令和数据。指令是行为,数据影响到指令。如前进3米,前进是指令,3米是数据。

然后我们再看一下各个类的含义。

Command和ConcreteCommand是命令,有Excute函数,代表要做的行为。

ConcreteCommand调用Excute(),最终调用Receiver的Action。这意味ConcreteCommand只是一个容器,真正的操作逻辑在Receiver中。

Invoker包含了所有Command,控制Command何时执行Excute()。

现在我们将UML简化,把Invoker、Receiver去掉,看看是否容易理解了。

图片

通过这个简洁版UML,我们来看一下为什么要用命令模式。

命令包括指令和数据,指令其实对应着操作,操作在代码中对应着函数。

命令模式其实是把函数封装成对象,系统能对对象进行各种操作,如排队执行、记录日志、撤销等。

为什么要将函数包装成对象呢?C、C++、Go支持函数指针,但并不是所有语言都有这种特性,这时命令模式就起作用了。而且即使语言支持函数指针,命令的数据部分怎么存放仍是一个问题。

所以简单理解,命令模式就是把请求打包成一个一个Command对象,存储起来,系统根据实际需求进行处理。

2.应用场景

大家可能感觉命令模式与MQ、工厂模式一样,其实在细节上是有区别的:

  • MQ只包含数据,不包含行为,命令模式两者都包含
  • 工厂模式需要实时执行,但命令模式可以进行存储,延后执行

命令模式我从来没有用过。《设计模式之美》里讲了游戏研发的一种通用架构:客户端的请求被服务端存储起来,服务端有单独线程处理这些请求。那我们就按这个场景写一下代码实现。

3.代码实现

package main

import "fmt"

/**
 * @Author: Jason Pang
 * @Description: 命令接口
 */
type Command interface {
   Execute()
}

/**
 * @Author: Jason Pang
 * @Description: 移动命令
 */
type MoveCommand struct {
   x, y int64
}

/**
 * @Author: Jason Pang
 * @Description: 如何移动
 * @receiver m
 */
func (m *MoveCommand) Execute() {
   fmt.Printf("向右移动%d,向上移动%d \n", m.x, m.y)
}

/**
 * @Author: Jason Pang
 * @Description: 攻击命令
 */
type AttackCommand struct {
   skill string
}

/**
 * @Author: Jason Pang
 * @Description: 如何攻击
 * @receiver a
 */
func (a *AttackCommand) Execute() {
   fmt.Printf("使用技能%s\n", a.skill)
}

/**
 * @Author: Jason Pang
 * @Description: 记录命令
 * @param action
 * @return Command
 */
func AddCommand(action string) Command {
   if action == "attack" {
      return &AttackCommand{
         skill: "野蛮冲撞",
      }
   } else { //默认是移动
      return &MoveCommand{
         x: 10,
         y: 20,
      }
   }
}

func main() {
   //将命令记录
   lc := make([]Command, 0)
   lc = append(lc, AddCommand("attack"))
   lc = append(lc, AddCommand("move"))
   lc = append(lc, AddCommand("move"))
   lc = append(lc, AddCommand("attack"))

   //执行命令
   for _, c := range lc {
      c.Execute()
   }
}

输出:

➜ myproject go run main.go

使用技能野蛮冲撞

向右移动10,向上移动20

向右移动10,向上移动20

使用技能野蛮冲撞

通过上面的代码,大家应该能够理解命令模式了。可以看出,对不同请求,生成不同的Command,Command中包含对应的数据与操作。这也是模式定义中说到的”对请求排队或记录请求日志,以及支持可撤销的操作“。

总结

设计模式是为了解决现实中的问题,我们需要和具体场景相绑定。在解决问题的时候,采用的是不是标准的设计模式并不重要,模式只是手段,手段需要为达成目的服务。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

往期文章回顾:

  1. 设计模式
  2. 招聘
  3. 思考
  4. 存储
  5. 算法系列
  6. 读书笔记
  7. 小工具
  8. 架构
  9. 网络
  10. Go语言
相关文章
|
2月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
3月前
|
设计模式 Go
go 设计模式之观察者模式
go 设计模式之观察者模式
|
3月前
|
设计模式 存储 Java
【十二】设计模式~~~行为型模式~~~命令模式(Java)
文章详细介绍了命令模式(Command Pattern),这是一种对象行为型模式,用于将请求封装成对象,实现请求发送者与接收者的解耦,从而降低系统耦合度、提高灵活性,并支持命令的排队、记录、撤销和恢复操作。通过案例分析、结构图、时序图和代码示例,文章展示了命令模式的组成部分、实现方式和应用场景,并讨论了其优点、缺点和适用情况。
|
4月前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
72 8
|
4月前
|
设计模式 JavaScript API
js设计模式【详解】—— 命令模式
js设计模式【详解】—— 命令模式
44 6
|
5月前
|
设计模式
命令模式-大话设计模式
命令模式-大话设计模式
|
5月前
|
设计模式 Java uml
必知的技术知识:JAVA【设计模式】命令模式
必知的技术知识:JAVA【设计模式】命令模式
29 0
|
5月前
|
设计模式 Java
Java设计模式之命令模式详解
Java设计模式之命令模式详解
|
5月前
|
设计模式
设计模式之命令模式
设计模式之命令模式
|
6月前
|
设计模式 存储 Java
【搞懂设计模式】命令模式:从遥控器到编程的妙用!
【搞懂设计模式】命令模式:从遥控器到编程的妙用!
74 0