这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
go语言设计模式 - 命令模式
1. 介绍
将请求封装成一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。
2. 类图
Command(抽象方法类): 抽象命令一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
ConcreteCommand(具体命令类): 具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action).
Invoker(调用者): 调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接受者,因此它至于抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接受者的相关操作。
Receiver(接收者): 接收者执行与请求相关的操作,它具体实现对请求的业务处理。
3. 代码实现
package main
import "fmt"
type Doctor struct{}
func (d *Doctor) TreatEye() {
fmt.Println("医生治疗眼睛")
}
func (d *Doctor) TreateNose() {
fmt.Println("医生治疗鼻子")
}
// 抽象的命令
type Command interface {
Treat()
}
// 治疗眼睛的病单
type CommandTreatEye struct {
doctor *Doctor
}
func (cmd *CommandTreatEye) Treat() {
cmd.doctor.TreatEye()
}
// 治疗鼻子的病单
type CommandTreatNose struct {
doctor *Doctor
}
func (cmd *CommandTreatNose) Treat() {
cmd.doctor.TreateNose()
}
// 护士 命令的调用者
type Nurse struct {
CmdList []Command // 收集的命令集合
}
// 业务层
func (n *Nurse) Notify() {
if n.CmdList == nil {
return
}
for _, cmd := range n.CmdList {
cmd.Treat()
}
}
// 病人 业务层
func main() {
// 依赖病单 通过填写病单 让医生看病
doctor := new(Doctor)
cmdEye := CommandTreatEye{doctor: doctor}
cmdNose := CommandTreatNose{doctor: doctor}
// 护士
nurse := new(Nurse)
// 收集管理病单
nurse.CmdList = append(nurse.CmdList, &cmdEye, &cmdNose)
// 诊断
nurse.Notify()
}
4. 适用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无需知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。
- 系统需要再不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以由不同的生命期,换言之,最初的请求发出者可能已经不存在了,而命令对象本身仍然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可以通过请求日志等机制来具体实现。
- 系统需要将一组操作组合在一起形成宏命令。