Go语言命令模式用函数类型或结构体实现:func()适合无状态操作,结构体支持Undo等复杂逻辑;需分离命令创建与执行,警惕闭包变量复用和值拷贝陷阱。
Go 语言没有类继承和接口强制实现,命令模式不能照搬 Java 那套写法;它更适合用函数类型、结构体组合和闭包来轻量实现——核心是把「请求」封装成可传递、可存储、可延迟执行的
值。
用函数类型定义 Command 最简洁
Go 中最自然的命令抽象就是
。不需要额外接口或基类,直接把操作逻辑封装成无参无返回值的函数即可被统一调度。
适合一次性、无状态的操作(如日志记录、通知触发)
避免冗余结构体定义,降低认知负担
注意:若需撤销(
),纯函数类型无法自带反向逻辑,必须搭配闭包捕获上下文
示例:
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
需要 Undo 或状态管理时,用结构体 + 方法实现
当命令要支持撤销、重做、参数检查或执行前校验时,结构体方式更可控。关键不是“实现某个接口”,而是确保结构体同时拥有
和
方法。
立即学习
“
go语言免费学习笔记(深入)
”;
字段应只保存执行所需最小上下文(如 ID、旧值、依赖对象指针)
避免在
中做副作用以外的事(比如发起 HTTP 请求后又修改本地缓存)
撤销操作不是“反向执行”,而是恢复到执行前一致状态;例如保存前先读取旧值,
时写回
示例:
命令队列与执行器要分离关注点
别把命令创建、排队、执行、错误处理全塞进一个地方。典型错误是让
直接 new 命令实例——这会导致耦合、难测试、无法复用命令。
命令由业务层构造并传入执行器(依赖注入)
执行器只负责调用
,记录失败、支持批量/串行/超时控制
如果要支持事务语义(全部成功或全部回滚),需在执行器中维护已成功命令列表,失败时逆序调用
示例执行逻辑片段:
小心 Go 的值拷贝与闭包变量陷阱
命令常在循环中批量创建,容易因变量复用导致所有命令实际引用同一个值。这是 Go 中最隐蔽也最高频的命令模式 bug。
错误写法:
—— 所有闭包共享最后一个
正确写法:显式传参或用局部变量绑定,例如
结构体命令同理:循环中用
创建指针,但确保字段值是独立拷贝而非引用原切片元素
这点不注意,命令看起来都“注册”了,执行时却全作用在同一个对象上。
Commandfunc()Undotype Command func()
func NewSaveCommand(repo *Repository, data interface{}) Command {
return func() {
repo.Save(data)
}
}
// 使用
cmd := NewSaveCommand(userRepo, user)
cmd() // 执行
Execute()Undo()Execute()Undotype UpdateUserCommand struct {
repo *UserRepository
userID string
newName string
oldName string // 执行前捕获,用于 Undo
}
func (c *UpdateUserCommand) Execute() {
c.oldName = c.repo.GetName(c.userID)
c.repo.UpdateName(c.userID, c.newName)
}
func (c *UpdateUserCommand) Undo() {
c.repo.UpdateName(c.userID, c.oldName)
}
CommandExecutorExecute()Undo()func (e *CommandExecutor) ExecuteAll(cmds []Command) error {
for _, cmd := range cmds {
if err := e.executeOne(cmd); err != nil {
return err
}
}
return nil
}
for _, id := range ids { cmds = append(cmds, func(){ do(id) }) }idfor _, id := range ids { id := id; cmds = append(cmds, func(){ do(id) }) }&UpdateUserCommand{...}