GoLang设计模式09 - 命令模式(行为型)
命令模式是一种行为型模式。它建议将请求封装为一个独立的对象。在这个对象里包含请求相关的全部信息,因此可以将其独立执行。
在命令模式中有如下基础组件:
- Receiver:唯一包含业务逻辑的类,命令对象会将请求传递给它,请求的最终处理者
- Command:组装了一个
Receiver成员,并绑定实现了Receiver的一个特定行为 - Invoker:请求的发送者,组装了
Command成员,通过调用Command实例的execute()方法来触发对应的指令 - Client:通过将
Receiver实例传递给Command构造器来创建Command对象,之后会将创建的对象同Invoker绑定。
还是通过一个具体的场景来理解下命令模式是怎样运行的。以打开电视这个行为举例,我们可以通过如下方式打开电视:
- 通过遥控器开关打开电视
- 通过电视上的开关打开电视
在这个场景中,我们有一个指令(Command)是“打开电视”,指令的接收者(Receiver)当然就是电视(TV)了,当我们执行(execute)指令时,相关指令就会让电视打开(TV.on())。
再明确下这个场景中的所有组件:
Receiver是TVCommand只有一个,是打开电视:ON,这个指令需要组装TV成员Invoker是遥控打开或开关打开这两种方式,它们会组装ON指令成员。
注意,这里我们将“打开电视”这个请求封装到了一个ON指令对象中,这个指令可以被不同的调用方调用。在ON指令中嵌入了TV实例,可以被独立执行。
再举个例子,想想PhotoShop这个软件,在PhotoShop中,要执行“保存”操作有三种方式:
- 从右键菜单中执行保存
- 从工具栏菜单中执行保存
- 使用Ctrl+S快捷键
这三种操作做的是同一件事情:保存正在编辑的图片。这三种操作的保存行为可以抽象为一个“Save”指令对象,而正在被编辑的图片就可以视为一个Receiver。
现在总结下使用命令对象的好处:
- 抽象出了潜藏的真实业务逻辑,并将其和具体的操作解耦
- 不需要为每个调用者创建不同的处理器
- 指令对象包含了执行所需的全部信息,因此它也适用于需要延迟执行的场景
看下UML类图:
- 注意下
Invoker是怎样嵌入指令对象的。当一个请求发送给Invoker的时候,Invoker会将这个请求传递给其嵌入的命令对象。 - 所有具体的指令类都会组装一个
Receiver成员属性。
代码如下:

代码如下:
1 //(指令 interface) 2 type command interface { 3 execute() 4 } 5 //(Receiver interface) 6 type device interface { 7 on() 8 off() 9 } 10 //(Receiver) 11 type tv struct { 12 isRunning bool 13 } 14 15 func (t *tv) on() { 16 t.isRunning = true 17 fmt.Println("Turning tv on") 18 } 19 20 func (t *tv) off() { 21 t.isRunning = false 22 fmt.Println("Turning tv off") 23 } 24 //(指令) 25 type onCommand struct { 26 device device 27 } 28 29 func (c *onCommand) execute() { 30 c.device.on() 31 } 32 //(指令) 33 type offCommand struct { 34 device device 35 } 36 37 func (c *offCommand) execute() { 38 c.device.off() 39 } 40 //(Invoker,开关打开电视) 41 type button struct { 42 command command 43 } 44 45 func (b *button) press() { 46 b.command.execute() 47 } 48 //(Client) 49 func main() { 50 51 tv := &tv{} 52 onCommand := &onCommand{ 53 device: tv, 54 } 55 56 offCommand := &offCommand{ 57 device: tv, 58 } 59 60 onButton := &button{ 61 command: onCommand, 62 } 63 64 onButton.press() 65 66 offButton := &button{ 67 command: offCommand, 68 } 69 offButton.press() 70 }
运行结果:
1 Turning tv on 2 Turning tv off
浙公网安备 33010602011771号