新闻中心
如何使用Golang实现命令模式撤销操作_使用Command Pattern支持撤销功能
Go中实现命令模式支持撤销的关键是定义含Execute()和Undo()方法的Command接口,各具体命令结构体封装必要状态并显式实现双向逻辑,调用器用切片维护历史栈实现单步撤销。

在 G
o 中实现命令模式并支持撤销操作,关键在于将每个可执行动作封装为独立的 Command 对象,并维护一个命令历史栈(通常用切片实现),同时要求每个命令自身具备 Execute() 和 Undo() 方法。
定义统一命令接口
Go 没有传统意义上的抽象类,但可通过接口定义契约:
type Command interface {
Execute()
Undo()
}
所有具体命令(如“添加用户”、“删除文件”)都必须实现这两个方法。注意:Undo 的逻辑不是自动反向执行,而是由开发者显式编写——比如 DeleteFileCommand 的 Execute() 删除文件,Undo() 就需恢复备份或重新创建该文件。
实现具体命令并保存必要状态
每个命令结构体需内嵌执行所需的数据,确保 Undo() 有足够上下文回退。例如:
GemDesign
AI高保真原型设计工具
652
查看详情
type AddUserCommand struct {
userStore *[]string
userName string
}
func (c *AddUserCommand) Execute() {
*c.userStore = append(*c.userStore, c.userName)
}
func (c *AddUserCommand) Undo() {
users := *c.userStore
if len(users) > 0 && users[len(users)-1] == c.userName {
*c.userStore = users[:len(users)-1]
}
}
- 避免在
Execute()中修改外部状态后丢失还原依据(如不记录被删文件名就无法恢复) - 若操作涉及外部系统(如数据库),
Undo()应是幂等且尽量轻量的补偿动作 - 命令对象应是不可变的(或至少其字段在 Execute 后不再变更),防止多线程下状态错乱
构建支持撤销的命令调用器
用切片模拟栈,按顺序记录已执行命令,提供 Execute()、Undo() 和可选的 Redo():
type CommandInvoker struct {
history []Command
undone []Command // 可选:用于 redo
}
func (i *CommandInvoker) Execute(cmd Command) {
cmd.Execute()
i.history = append(i.history, cmd)
i.undone = nil // 执行新命令后清空 redo 栈
}
func (i *CommandInvoker) Undo() {
if len(i.history) == 0 {
return
}
last := i.history[len(i.history)-1]
last.Undo()
i.history = i.history[:len(i.history)-1]
i.undone = append(i.undone, last)
}
- 每次
Undo()只撤回最近一次Execute(),符合常规交互直觉 - 若需多级撤销,直接循环调用
Undo()即可,无需额外参数 - 历史栈本身不持有命令执行结果,只负责调度;状态管理完全交给命令和接收者(receiver)
注意事项与常见陷阱
命令模式在 Go 中落地时容易忽略几点:
- 不要让命令依赖全局变量或单例——这会让测试困难、Undo 不可靠
- 避免在
Undo()中抛出 panic;建议返回 error 或静默失败(如文件已存在则跳过恢复) - 若命令耗时长(如网络请求),考虑加超时或上下文控制,但
Undo()也应同样支持 cancel - 撤销功能会增加内存占用,长期运行服务中可限制
history最大长度(如只保留最近 100 条)
基本上就这些。核心是把“做什么”和“谁来做”解耦,再让每个“做什么”自己知道怎么撤回——Go 的接口 + 结构体组合,足够干净地表达这个意图。
以上就是如何使用Golang实现命令模式撤销操作_使用Command Pattern支持撤销功能的详细内容,更多请关注其它相关文章!
# 检测方法
# 寮步seo优化运营
# 新加坡小吃推广网站大全
# 未来互联网营销推广
# 绥德营销软件推广招聘
# 大冶营销推广
# 公司网站建设怎样做
# 山东网站推广选哪家
# 中文网站怎样推广赚钱快
# 沧州网站推广招商
# 手机怎样搜索关键词排名
# 所需
# 是由
# go
# 应是
# 可选
# 全局变量
# 布尔
# 做什么
# 多线程
# 如何使用
# red
# 内存占用
# 栈
# app
# golang
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
如何在网页中实现特定地点的随机图片展示
c++项目目录结构应该如何组织_c++工程化项目结构规范
漫蛙manwa2最新登录网址_漫蛙manwa2手机网页版入口
mcjs网页版流畅运行 mcjs低配电脑畅玩入口
品牌机怎么重装系统 联想/戴尔/惠普笔记本恢复出厂系统教程
淘宝网网页版登录入口 淘宝官方网页版快捷登录
Excel中VLOOKUP的第四个参数是干什么用的_Excel VLOOKUP第四参数作用解析
如何高效处理PHP中的Excel数据导入导出?PortPHP/Spreadsheet助你轻松搞定!
QQ官网正版登录链接 QQ在线登录入口最新
c++如何实现一个简单的软件渲染器_c++从零开始的3D图形学
2025AO3夸克浏览器通道_AO3手机HTTPS安全入口分享
深入理解Go语言中的指针类型:以*string为例
AO3同人作品网入口 AO3搜索引擎官网永久地址
qq邮箱发邮件给国外发不出去_QQ邮箱国际邮件发送失败原因与解决
J*aScript中如何高效提取对象指定属性
J*aScript对象创建方式_J*aScript设计模式应用
理解Python模块与全局变量的作用域管理
QQ邮箱网页版快速登录 QQ邮箱邮箱账号官方入口地址
React Router 嵌套组件中 URL 重定向问题的解决方案
Go语言中的*string:深入理解字符串指针
构建轻量级网站内部消息系统:Formspree 集成指南
《GTA6》开发画面疑似泄露!这次可不是AI了
天眼查企业查询官网入口 天眼查官方网页版查询
斑马英语APP如何开启夜间护眼阅读_斑马英语APP夜间模式与低蓝光设置教程
漫蛙漫画官方首页 漫蛙2漫画在线阅读入口
LINUX的perf命令入门_LINUX官方性能分析工具的使用与解读
Angular中父组件异步更新子组件复选框状态的实践指南
天眼查怎么看公司融资情况 天眼查企业融资历史查询步骤【攻略】
qq游戏网页版直接玩_qq游戏免下载快速入口
2026春节假期时间安排 2026春节假日查询
离线运行Go语言之旅:本地部署与GOPATH配置指南
如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题
必由学官方网站入口 必由学学生教师共用登录通道
我的世界mc.js免费游戏直接能玩 我的世界mc.js小游戏免费秒玩入口
《主播少女的秘密账号迷宫》首支宣传片
UC浏览器如何安装插件 UC浏览器添加扩展程序详细教程【进阶】
网易大神怎么保存别人动态的图片_网易大神动态图片保存方法
Linux如何构建多环境配置管理_Linux多环境配置方案
三星GalaxyZFold5怎样在相册制作折叠屏分镜_iPhone三星GalaxyZFold5相册制作折叠屏分镜【创意编辑】
C++如何打印当前代码行号与文件名_C++预定义宏FILE与LINE的使用
Google翻译怎么语音输入_Google翻译语音输入功能使用与设置方法
在VS Code中配置和运行Dart程序的完整步骤
Lar*el用户头像管理:实现图片缩放、存储与旧文件安全删除的最佳实践
铁路12306的积分有效期是多久_铁路12306积分有效期说明
sublime如何优雅地处理行尾空格_sublime自动清理多余空白字符配置
Python类型检查:优化关联可选属性的Mypy推断策略
在哪找SublimeJ远程工具_SFTP插件配置教程
在Qt QML中通过Python字典动态更新TextEdit内容的教程
MAC的“快捷指令”怎么同步到iPhone_MAC利用iCloud同步所有设备的自动化指令


2025-12-09
浏览次数:次
返回列表