GoLang设计模式08 - 命令模式
命令模式是一种行为型模式。它建议将请求封装为一个独立的对象。在这个对象里包含请求相关的全部信息,因此可以将其独立执行。
在命令模式中有如下基础组件:
- Receiver:唯一包含业务逻辑的类,命令对象会将请求传递给它,请求的最终处理者
- Command:组装了一个
Receiver
成员,并绑定实现了Receiver
的一个特定行为 - Invoker:请求的发送者,组装了
Command
成员,通过调用Command
实例的execute()
方法来触发对应的指令 - Client:通过将
Receiver
实例传递给Command
构造器来创建Command
对象,之后会将创建的对象同Invoker
绑定。
还是通过一个具体的场景来理解下命令模式是怎样运行的。以打开电视这个行为举例,我们可以通过如下方式打开电视:
- 通过遥控器开关打开电视
- 通过电视上的开关打开电视
在这个场景中,我们有一个指令(Command)是“打开电视”,指令的接收者(Receiver)当然就是电视(TV)了,当我们执行(execute)指令时,相关指令就会让电视打开(TV.on())。
再明确下这个场景中的所有组件:
Receiver
是TV
Command
只有一个,是打开电视:ON
,这个指令需要组装TV
成员Invoker
是遥控打开或开关打开这两种方式,它们会组装ON
指令成员。
注意,这里我们将“打开电视”这个请求封装到了一个ON
指令对象中,这个指令可以被不同的调用方调用。在ON
指令中嵌入了TV
实例,可以被独立执行。
再举个例子,想想PhotoShop这个软件,在PhotoShop中,要执行“保存”操作有三种方式:
- 从右键菜单中执行保存
- 从工具栏菜单中执行保存
- 使用Ctrl+S快捷键
这三种操作做的是同一件事情:保存正在编辑的图片。这三种操作的保存行为可以抽象为一个“Save”指令对象,而正在被编辑的图片就可以视为一个Receiver
。
现在总结下使用命令对象的好处:
- 抽象出了潜藏的真实业务逻辑,并将其和具体的操作解耦
- 不需要为每个调用者创建不同的处理器
- 指令对象包含了执行所需的全部信息,因此它也适用于需要延迟执行的场景
看下UML类图:
- 注意下
Invoker
是怎样嵌入指令对象的。当一个请求发送给Invoker
的时候,Invoker
会将这个请求传递给其嵌入的命令对象。 - 所有具体的指令类都会组装一个
Receiver
成员属性。
代码如下:
代码如下:
command.go(指令 interface)
1
2
3
|
type command interface { execute() } |
device.go(Receiver interface)
1
2
3
4
|
type device interface { on() off() } |
tv.go(Receiver)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import "fmt" type tv struct { isRunning bool } func (t *tv) on() { t.isRunning = true fmt.Println( "Turning tv on" ) } func (t *tv) off() { t.isRunning = false fmt.Println( "Turning tv off" ) } |
onCommand.go(指令)
1
2
3
4
5
6
7
|
type onCommand struct { device device } func (c *onCommand) execute() { c.device.on() } |
offCommand.go(指令)
1
2
3
4
5
6
7
|
type offCommand struct { device device } func (c *offCommand) execute() { c.device.off() } |
button.go(Invoker,开关打开电视)
1
2
3
4
5
6
7
|
type button struct { command command } func (b *button) press() { b.command.execute() } |
main.go(Client)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
func main() { tv := &tv{} onCommand := &onCommand{ device: tv, } offCommand := &offCommand{ device: tv, } onButton := &button{ command: onCommand, } onButton.press() offButton := &button{ command: offCommand, } offButton.press() } |
运行结果:
1
2
|
Turning tv on Turning tv off |
代码已上传至GitHub:github / zhyea / command
END!
仅是学习笔记,难免出错,望不吝指点
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)