设计模式-行为型-命令模式
命令模式,亦称 Action, Transaction, Command
views
| comments
命令模式#
命令模式是一种行为型设计模式,它可将请求转换成一个包含与该请求相关的所有信息的独立对象。这样的请求对象的封装存在以下好处:
- 能够根据不同的请求,将方法参数化
- 能有效延迟参数执行
- 能将请求放入到任务队列中,支持历史回滚,撤销操作
问题引入#
我们现在要开发一个包含多个不同用途按钮的工具栏,现在你已经开发好了一个Button
基类,支持点击并且生成各种对话框的通用按钮。但具体的业务代码还没有完全集成到上面,此时对于具体的业务,最简单的方法就是在需要添加业务的地方创建相应的按钮子类,OpenButton
, SaveBtton
, PrintButton
…子子孙孙无穷无尽也。
引入命令#
在一般的软件设计中,设计GUI时,优秀的设计总是会将开发分为两层进行开发。一层是GUI层,仅仅负责渲染界面的效果及展示,一层则是业务逻辑层,负责具体的点击事件的处理和操作。看起来就像这样:
命令模式的基本思想则是,不建议GUI对象直接提交这些请求,我们应该将请求的所有细节(调用的对象、方法签名)抽取出来组成命令类(Command),在这个中间类中仅仅包含一个用来触发实际请求的方法。
这样一来,GUI无需了解业务逻辑对象对该请求的响应如何,它需要做的仅仅是出发命令,命令对象会自行处理所有请求的细节,命令类成为了减少GUI和业务逻辑层之间耦合的中间层。
整体结构#
代码示例#
在日常生活中,我们可以通过以下方式打开电视机:
- 按下遥控器上的ON按钮
- 按下电视机本体上的ON按钮
在这个例子中,电视机可以作为Retriever
接收者,以ON/OFF为命令对象,而实质上这里存在着两个请求者TV
,遥控器。
// 请求者
type Button struct {
command Command
}
func (b *Button) Press() {
b.command.Execute()
}
// 命令对象接口
type Command interface {
Execute()
}
// 具体命令对象
type OnCommand struct {
d Device
}
func (o *OnCommand) Execute() {
o.d.On()
}
type OffCommand struct {
d Device
}
func (o *OffCommand) Execute() {
o.d.Off()
}
// 接收者接口
type Device interface {
On()
Off()
}
type TV struct {
isRunning bool
}
func (t *TV) On() {
t.isRunning = true
}
func (t *TV) Off() {
t.isRunning = false
}
// 测试入口
// 测试入口
func main() {
tv := &TV{}
onCommand := &OnCommand{d: tv}
offCommand := &OffCommand{d: tv}
onButton := &Button{command: onCommand}
offButton := &Button{command: offCommand}
onButton.Press()
offButton.Press()
}
goHow To Implement#
- 声明仅有一个执行方法的命令接口。
- 抽取请求并使之成为实现命令接口的具体命令类。 每个类都必须有一组成员变量来保存请求参数和对于实际接收者对象的引用。 所有这些变量的数值都必须通过命令构造函数进行初始化。
- 找到担任发送者职责的类。 在这些类中添加保存命令的成员变量。 发送者只能通过命令接口与其命令进行交互。 发送者自身通常并不创建命令对象, 而是通过客户端代码获取。
- 修改发送者使其执行命令, 而非直接将请求发送给接收者。
- 客户端必须按照以下顺序来初始化对象:
- 创建接收者。
- 创建命令, 如有需要可将其关联至接收者。
- 创建发送者并将其与特定命令关联。
Wrap up#
- 如果我们需要通过操作来参数化对象,可以使用命令模式
- 如果我们需要将操作放入到队列中、或者远程执行操作
- 如果需要实现操作回滚,撤销恢复等操作