命令模式是什么
一些比较抽象的定义
GoF: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化
本书作者:命令是具现化的方法调用
具现化, 可以解释成将某事物作为“第一公民”对待,意味着我们可以把它存储在变量中传给函数使用。即方法调用被存储在对象中。
此时脑海里会出现:“回调”、“函数指针”、"闭包"等关键词
GoF: 命令模式是一种回调的面向对象实现
个人理解
游戏中某个单一的系统功能需要兼容多种不同的使用状态,比如实现一个gta作弊码功能,可能会有各种各样的作弊码,如果在一个系统里塞入各种功能的实现就会使得这套系统变得很复杂。此时需要在实现层和业务逻辑层中添加一个托管层,系统只关心我要收集一系列命令,至于命令做什么不是该系统关心的内容。
在命令查询职责分离模式中,会将所有的操作分成查询和命令两种,对数据的操作会封装成一个个命令,好处是数据修改很清晰。
命令模式能做什么
配置输入
1 | void InputHandler::handleInput() |
上面代码将按键和输入绑定在了一起,意味着这是一个不允许玩家随意改键的游戏,显然不是一个现代游戏应有的表现(等着被喷吧
1 |
|
做了一层间接寻址,将输入和具体行为分开了,此时每个按键可以绑定不同的Command
角色说明
上节的跳跃命令可以控制角色跳跃,但其没有任何参数传入,意味着命令要自己去寻找被控单位,且很有可能只能控制玩家角色。
1 |
|
如果将被控单位作为参数传入,可以使用这个类让游戏中的任何角色跳来跳去了,除了可以让玩家控制游戏中的任何角色外,这样做的好处是其他系统也可以使用命令控制单位,比如ai、寻路等系统,且命令还可以支持队列,实现按顺序控制某个单位。
网络同步中也有用命令来同步,将玩家的输入抽象成一个个命令,其他端只需要按顺序去还原命令即可。说到还原,当有了一系列命令以后,游戏的回放系统也自然实现了。
撤销和重做
命令模式最经典的使用方式,每个命令需要实现调用和回滚接口,意味着每个指令都可以回滚。
1 |
|
使用指令列表还可以多重撤销
用类还是用函数?
命令与第一公民函数或者闭包类似,如果使用的语言支持闭包,那可以直接使用闭包,在某种程度上说,命令模式是为一些没有闭包的语言模拟闭包(个人理解更是提供了一种设计思路,使用类或者函数都可以,但闭包的自动包含数据字段还是挺危险的,过于自动化而很难看清包装的真正状态有哪些)
如果使用了类来实现,很多命令都是一致的,可以使用对象池来优化
引用
1 |