[go] 命令模式

简介: [go] 命令模式

命令模式


将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。


模型说明



  • 触发者类负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。触发命令,而不同接受者直接发送请求。注意,发送者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令。


  • 命令接口通常仅声明一个执行命令的方法。


  • 具体命令会实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象。但为了简化代码,这些类可以进行合并。


  • 接收对象执行方法所需的参数可以声明为具体命令的成员变量。可以将命令对象设为不可变,仅允许通过构造函数对这些成员变量进行初始化。


  • 接收者类包含部分业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。


  • 客户端会创建并配置具体命令对象。客户端必须将包括接收者实体在哪的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联。


优缺点


1.优点

  • 单一职责原则。 你可以解耦触发和执行操作的类。
  • *开闭原则。*你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
  • 你可以实现撤销和恢复功能。
  • 你可以实现操作的延迟执行。
  • 你可以将一组简单命令组合成一个复杂命令。


2.缺点

  • 代码可能会变得更加复杂, 因为你在发送者和接收者之间增加了一个全新的层次。


使用场景


  • 如果你需要通过操作来参数化对象, 可使用命令模式。
  • 如果你想要将操作放入队列中、 操作的执行或者远程执行操作, 可使用命令模式。
  • 如果你想要实现操作回滚功能, 可使用命令模式。


参考代码

// command.go
// 命令接口
type command interface {
  execute()
  undo()
}
// concrete_command.go
// 具体命令
type light struct{}
func (l *light) label() string {
  return "light"
}
func (l *light) on() {
  fmt.Println("light is on")
}
func (l *light) off() {
  fmt.Println("light is off")
}
type lightOnCommand struct {
  l *light
}
func (c *lightOnCommand) execute() {
  c.l.on()
}
func (c *lightOnCommand) undo() {
  c.l.off()
}
type lightOffCommand struct {
  l *light
}
func (c *lightOffCommand) execute() {
  c.l.off()
}
func (c *lightOffCommand) undo() {
  c.l.on()
}
const (
  labelNoCommand = "on_command"
)
type noCommand struct{}
func (n *noCommand) execute() {
  fmt.Println("no command executed")
}
func (n *noCommand) undo() {
  fmt.Println("no command undo")
}
// invoker.go
// 触发者
type remoteController struct {
  onCommands  map[string]command
  offCommands map[string]command
  preCmd      command
}
func createSimpleRemoteController() *remoteController {
  rc := &remoteController{
    onCommands:  make(map[string]command),
    offCommands: make(map[string]command),
  }
  // 这里处理为了没有找到插槽时的表现
  noCMD := new(noCommand)
  rc.onCommands[labelNoCommand] = noCMD
  rc.offCommands[labelNoCommand] = noCMD
  // 初始化的时候,没有上一次点击的按钮,所以使用 noCommand
  rc.preCmd = noCMD
  return rc
}
func (rc *remoteController) setCommand(label string, onCMD, offCMD command) {
  rc.onCommands[label] = onCMD
  rc.offCommands[label] = offCMD
}
func (rc *remoteController) onButtonWasPressed(label string) {
  cmd := rc.onCommands[label]
  if cmd == nil {
    cmd = rc.onCommands[labelNoCommand]
  }
  cmd.execute()
  rc.preCmd = cmd
}
func (rc *remoteController) offButtonWasPressed(label string) {
  cmd := rc.offCommands[label]
  if cmd == nil {
    cmd = rc.offCommands[labelNoCommand]
  }
  cmd.execute()
  rc.preCmd = cmd
}
func (rc *remoteController) undo() {
  rc.preCmd.undo()
}
// main.go
// 客户端
func main() {
  simpleLight := new(light)
  lightOnCmd := &lightOnCommand{l: simpleLight}
  lightOffCmd := &lightOffCommand{l: simpleLight}
  rc := createSimpleRemoteController()
  rc.setCommand(simpleLight.label(), lightOnCmd, lightOffCmd)
  rc.onButtonWasPressed(simpleLight.label())
  rc.offButtonWasPressed(simpleLight.label())
  rc.undo()
  rc.onButtonWasPressed("coffeeMachine")
}


输出:


light is on 
light is off 
light is on 
no command executed
相关文章
|
Shell Go
Go 语言入门很简单:Go 语言执行 Shell 命令(下)
Exec 是 os 包中的一个子包,它可用于使用 Go 运行外部命令。Go exec 命令教程展示了如何在 Golang 中执行 shell 命令和程序。
|
3月前
|
Go 容器
|
3月前
|
存储 Unix 测试技术
解释Go中常见的I/O模式
解释Go中常见的I/O模式
|
3月前
|
设计模式 存储 Go
|
3月前
|
存储 设计模式 Go
|
3月前
|
缓存 算法 Go
|
3月前
|
缓存 中间件 应用服务中间件
|
4月前
|
Go
go 常用命令总结
go 常用命令总结
28 0
|
设计模式 Go
Go的状态模式
状态模式是一种行为设计模式,它允许对象在内部状态发生改变时改变其行为。该模式将对象的行为委托给表示不同状态的对象,从而实现了状态的切换。
59 0
|
6月前
|
存储 Go C语言
go 基本语法
go 基本语法
44 0