[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
相关文章
|
Java 编译器 Go
Go 语言 入门 && 基于 GoLand 2023.1 创建第一个Go程序
Go 语言 入门 && 基于 GoLand 2023.1 创建第一个Go程序
145 0
|
Shell Go
Go 语言入门很简单:Go 语言执行 Shell 命令(下)
Exec 是 os 包中的一个子包,它可用于使用 Go 运行外部命令。Go exec 命令教程展示了如何在 Golang 中执行 shell 命令和程序。
|
5月前
|
存储 Unix 测试技术
解释Go中常见的I/O模式
解释Go中常见的I/O模式
|
8月前
|
编译器 Go C语言
go 语言helloword
go 语言helloword
|
8月前
|
编译器 Go
Go 语言注释教程
注释是在执行时被忽略的文本。注释可用于解释代码,使其更易读。注释还可用于在测试替代代码时防止代码执行。Go支持单行或多行注释。
77 1
|
Shell Linux Go
Go 语言入门很简单:Go 语言执行 Shell 命令(上)
Exec 是 os 包中的一个子包,它可用于使用 Go 运行外部命令。Go exec 命令教程展示了如何在 Golang 中执行 shell 命令和程序。
|
Go 开发者
[Go开源工具] go-optioner:轻松生成函数选项模式代码
你是否使用过 functional options 函数选项模式?在使用时,你是否遇到过多字段的结构体而需要手动编写大量的设置选项函数的代码? 本文介绍了 go-opioner 开源工具的安装和使用,它能够根据结构体的定义,自动生成函数选项模式的代码。
144 0
|
Kubernetes Unix Shell
Go 语言现代命令行框架 Cobra 详解
Go 语言现代命令行框架 Cobra 详解
1253 0
|
Go 开发者 索引
Go代码格式化——gofmt的使用
Go代码格式化——gofmt的使用
1380 0
Go代码格式化——gofmt的使用