当前位置: 首页 > article >正文

[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

http://www.kler.cn/a/308590.html

相关文章:

  • docker:docker: Get https://registry-1.docker.io/v2/: net/http: request canceled
  • Vue 3 介绍及应用
  • 普通电脑上安装属于自己的Llama 3 大模型和对话客户端
  • 浅谈C#之内存管理
  • 【再谈设计模式】抽象工厂模式~对象创建的统筹者
  • 深入探讨 MySQL 配置与优化:从零到生产环境的最佳实践20241112
  • 电信创维光猫DT741超级密码
  • 【LeetCode】每日一题 2024_9_13 预算内的最多机器人数目(滑动窗口、单调队列)
  • 文件标识符fd
  • 嵌入式Linux学习笔记(5)-进程间常见通讯方式(c语言实现)
  • 09_Python流程控制_分支
  • win10怎么配置dnat规则,访问win10的网口A ip的6443端口,映射到1.1.1.1的6443端口去
  • Android 源码集成可卸载 APP
  • go多线程
  • python-在PyCharm中使用PyQt5
  • 【C++】多态详解
  • mysql学习教程,从入门到精通,SQL IN BETWEEN 运算符(13)
  • 基于STM32F407ZGT6——看门狗
  • new/delete和malloc/free到底有什么区别
  • docker镜像结构
  • 代码随想录:动态规划4-5
  • Java技术深度探索:高并发场景下的线程安全与性能优化
  • java面试题-Sql 语句的执行顺序
  • 【SOP】使用MMDeploy将MMAction2的模型转换为TensorRT
  • 二叉树的前中后序遍历(递归法)( 含leetcode上三道【前中后序】遍历题目)
  • java-lambda-常用方法总结汇总