Ruby设计模式编程中命令模式的使用解析
时间:2026-08-17 | 作者:多维游侠 | 阅读:0在对象行为型模式里,命令模式的使用率一直很高,别名也挺多——Action、Transaction,本质都是一回事。
意图
命令模式的核心意图很清晰:把请求本身封装成对象。
这样一来,你就可以对不同请求进行参数化、排队、记录日志,甚至支持取消操作。
这里所说的“不同请求”,其实就意味着变化。
也就是说,请求本身是一个可能扩展的功能点。
动机
动机也很直白:方便扩展。
不想因为增加一个新功能,就把原有的代码翻个底朝天。
结构
协作说明
参与的角色各司其职:
- Command:声明一个接口,用来实现某个操作。
- ConcreteCommand:把动作与 Receiver 对外绑定,通过调用 Receiver 对象的相应方法来实现 Command 的方法。
- Client:创建 ConcreteCommand 对象,并指定它的 Receiver。
- Invoker:要求这个 Command 去实现请求。
- Receiver:真正知道如何处理具体请求的类。
整个流程是这样的:
- 客户端先创建一个具体的 Command 对象,并指定好接收者。
- 调用者把 Command 对象存下来。
- 然后通过执行它的 Execute 方法来实现请求。
- 如果命令支持撤销,具体对象在执行前会先把相关状态存起来。
- 最后,具体的 Command 对象通过调用接收者的方法,完成相应的请求。
适用性
什么时候该用命令模式?
- 类似 MenuItem 的场景,需要把待执行的动作抽象出来,参数化某个对象。
- 需要在不同时刻指定、排列和执行请求。
- 需要支持撤销操作。
- 需要支持修改日志。
- 在基于原语操作之上构建一个高层操作系统——说白了就是事务。
说到动态性,Ruby 中的 block 其实就是一种命令模式。
效果
命令模式把调用者与接收者解耦。换句话说,就是调用与实现分开。
调用者想实现功能,只需要调用 Command 接口的 Execute 方法就行。
具体的 Commands 对象是第一层对象,它们可以像其他对象一样被扩展或操作。
你可以把多个 Commands 对象组合成一个组合命令。
这其实是组合模式的一个实例,命令排队也是它的特殊情况。
更重要的是,你可以轻松地添加新的命令,完全不需要修改现有代码。
这一点正好符合开闭原则——对修改关闭,对扩展开放。
实现时需要考虑的问题
有两个问题值得琢磨:
- 命令对象应该达到什么智能程度?
- 如何支持撤销和重做?
误用
别把它想得太玄乎。
命令模式不是说“做这个”,而是说“记住这个如何做”,然后稍后再“按照我刚才要你记的方法做这个”。
另外,撤销操作要格外小心。
很多操作是破坏性的,比如删除文件。一旦撤了,文件可能就找不回来了。
类图
Ruby 代码示例
来看一段 Ruby 代码示例:
class Button
attr_accessor :name, :command
def initialize name, command
@name = name
@command = command
end
def do_something
@command.execute
end
end
class Command
def execute
"root execute"
end
end
class PaintCommand < Command
def execute
"draw something"
end
end
class VocalCommand < Command
def execute
"talk something"
end
end
paintCommand = PaintCommand.new
vocalCommand = VocalCommand.new
button = Button.new("button", paintCommand)
p button.do_something
button.command = vocalCommand
p button.do_something
这里定义了一个主体类 Button,它聚合了一个命令对象 Command。
同时声明了三个具有继承关系的命令类:Command、PaintCommand 和 VocalCommand。
系统里可能有很多 Button,每个 Button 要干的事都不一样。
也就是说,方法 do_something 里的代码是不确定的。
所以,把这部分代码分离到单独的对象里管理。
这个对象就叫命令对象。
命令对象只负责它该完成的任务或指令。
主体对象则可以根据需要,在任何时候调用要执行的命令。
从调用代码也能看出,切换当前 Button 的命令实现非常方便灵活,只需要调用 set 方法就行。
如果采用 Button 继承的方式,第一会造成类爆炸,第二在切换命令实现时,比这种方式要麻烦得多。
使用 Proc 实现命令模式
用 Ruby 的 Proc 来实现命令模式呢?更简洁:
class Button
attr_accessor :name
def initialize name, &command
@name = name
end
def do_something &command
command.call
end
end
paint_command = lambda do
p "paint something"
end
vocal_command = lambda do
p "talk something"
end
button = Button.new ("name")
button.do_something &vocal_command
button.do_something &paint_command
用 block 代替命令类,更简单、更易懂。
实际项目里用 Proc 还是用命令类,看情况来。
- 如果命令对象很复杂,有自己的状态和方法,那就选命令类。
- 如果只是处理点小事情,用 Proc 就挺好。
如果需要执行的命令很多,可以定义命令队列。
也就是一个命令里面管理多个命令,调用时挨个执行。
这一点和组合模式很像。
命令模式与观察者模式的区别
从某种角度看,观察者模式和命令模式有点相似。
它们都是把具有共同特征的对象聚合到自己类里,再根据情况调用。
但两者有明显的区别:用途不同。
- 观察者模式是为了让被观察者把变化通知给各个观察者。
- 而命令模式不关心是否要通知别的命令,命令对象只负责执行自己的任务或指令。
另外,命令模式可以记住前一次操作。
所以很多文本编辑器的撤销/重做功能,用的就是命令模式。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 使用RVM切换Ruby与Rails版本的实现方法
- 时间:2026-08-18
-
- Ruby语言是什么及入门使用方法
- 时间:2026-08-18
-
- Ruby on Rails网站项目搭建入门指南
- 时间:2026-08-18
-
- Ruby插入排序算法实现与二路插入排序代码示例
- 时间:2026-08-18
-
- Ruby图片滤镜算法实现代码与核心原理
- 时间:2026-08-18
-
- Ruby中Hash哈希结构基本操作方法详解
- 时间:2026-08-18
-
- Ruby面向对象编程:类方法与类扩展详解
- 时间:2026-08-18
-
- Ruby正则表达式语法详解与常用示例代码
- 时间:2026-08-18
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15

