设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。
一个设计模式,它的服务对象是高层模块,在设计模式中称为客户端,因此在描述设计模式的时候都是以客户端作为使用方来进行描述的。
设计模式在类间关系这个粒度上给出常见问题的解决方案。属于软件工程中逻辑架构设计中相当重要的一环。

快速查阅各类设计模式使用场景可参考此文:设计模式大全。


一、命令模式

定义: 把一个请求看做一个对象。这样用户就可以参数化客户端请求,实现请求的队列操作和日志管理,并且支持对操作进行撤销回退。(Encapsulate a request as an object, thereby letting users parameterize clients with different requests, queue or log requests, and support undoable operations.)

概述: 在软件开发过程中,我们可能会遇到这样的问题,在程序运行前,不知道命令(本文中请求和命令都指代同一个东西,即客户端发起的一个需要处理的操作)的执行者是谁,也不知道需要执行哪个命令。这时,我们可以使用命令模式将命令的发起者和命令的执行者解耦。把命令化作一个相对独立的对象,在发送者和执行者之间传输。程序运行时,再确定需要执行的命令和其执行者,并将命令移交给命令管理器处理。如果对命令模式稍微做一点改动,让每个命令提供执行的同时提供一个撤销的方法,就能够实现对命令的无限次撤销和重做,这在工程中具有非常广泛的应用。

1、核心思想

其实定义就已经讲出了命令模式的核心思想:把一个命令看做一个对象。这样做就能让命令拥有所有对象所拥有的优势。模式中的其他参与者都是围绕它来运作的。

2、类图

客户端|Client: 命令的发起者。确定接下来要执行什么命令。
调用者|Invoker: 命令的管理者,不关心每个命令具体是做什么内容,根据客户端的指示按序执行命令。
命令接口|ICommand:命令接口协议,确定每个命令需要提供的功能,这里要求每个命令类都提供执行方法。
具体命令|ConcreteCommand:包含执行一个命令所需的所有上下文信息,例如执行接收者的哪个方法,以及方法所需要的参数,甚至命令作为GUI 显示时的相关信息,例如应该显示的图标路径。具体命令类是命令模式中的核心节点,需要重点理解。

接收者|Receiver:命令所对应任务的实际执行者,位于调用链条的末端。

注意:客户端发起的每一个命令都是一个对象,即使是两条相同的命令,也是两个对象,而不是一个对象使用两次。

1)隐喻

下面通过一个隐喻来直观地展现命令模式的各个组成部分。

我们假设这样一个场景,公元 6011 年,人类在银河系的上千的星球建立了殖民地,其中大唐和盖亚是两个敌对的国家,大唐准备发动一场战争,冷月是一个大型特种部队的指挥官,拥有护卫舰、运输舰和战列舰等单位的使用权,该部队具有侦查、暗杀、破坏等多种职能。冷月所在星球只有一个小型港口提供舰船的发射与停靠,有一个指挥塔负责舰船的调度。

某天,冷月派遣一个破坏小队使用战列舰前往盖亚一个冷僻星球进行破坏占领,派遣一个侦查小队使用护卫舰先行侦查。同时派遣一个侦查小队使用运输舰前往友军三十四军团处待命。冷月将舰船出港许可发送给指挥塔,让指挥塔安排舰船出港。

在上面这个场景中,冷月是命令的发起人,是一个 Client,他根据实际的战斗需要安排舰船和作战人员。每一艘舰船都相当于是一个具体命令对象,舰长知道应该把舰船运送到什么地方(类比命令的执行环境),也知道舰船的乘坐人员(命令的接收者),指挥塔是 Invoker,它不关心出港舰船的类型以及舰船的运载人员,只是接受冷月的舰船的出港请求,然后安排对应舰船出港。当舰船到达目的地之后,舰船运载的作战人员会去执行具体的作战任务。

(笔者构思了好几种场景,发现命令对象化在现实中比较难以找到对应物,一个是因为命令对象具有接收者的引用,具有主动性,如果是人引用人会比较奇怪,相对来说具有主动性的机器容器引用人会比较合适,另一方面则是命令对象在 Client 眼中和 Invoker 眼中有不一样的抽象层次,也比较难以找到现实的对应物。科幻战争的这个场景虽然能够阐述命令模式的几个关键要素,但是场景本身有较多的干扰元素,有点过于复杂了,在实际中指挥塔不可能不关心舰船的类型,舰船作为命令的基本单位也有一点牵强。不过场景重在意会,加深理解,笔者认为该场景还是能够达成这一点,就放上来了,各位看官如果有更好的隐喻,欢迎在文后回复。)


^^ 版权衔接线 vv     全文出处:http://www.cnblogs.com/tangyikejun/p/5931571.html

3、应用场景以及优缺点

1)应用场景

适用于各种需要对命令进行调度管理以及传输的场景,也就是各种需要把命令包装成命令对象的场景。

1. 数据库的事务

每个事务作为一个命令对象。

2. 线程池

每个线程作为一个命令对象,客户端负责提供接收者

2)优点

  • 解开命令调用和命令执行之间的耦合
  • 方便命令的管理,包括命令组合、命令添加、命令记录和命令延时执行等
  • 容易扩展实现命令的撤销和重做

3)缺点

每个命令都需要一个具体命令类,如果系统的命令繁多,可能会影响开发效率。

二、游戏应用

1、适用场景

命令模式在工程中的许多应用是非常基础性的,在游戏与非游戏项目中都能使用。下面单以游戏应用为例进行介绍:

1) 玩家输入控制 & 菜单项

在控制玩家输入的时候,使用命令模式可以使得按键和按键对应的命令解绑,从而支持用户自定义,还可以把指令的触发和执行时间解绑,实现延时执行。对于多角色游戏,还能为玩家和AI之间提供一套通用的命令接口

2) 宏记录 & GM 指令

所谓宏,就是将一些命令组织在一起,作为一个单独命令完成一个特定任务。而宏记录是指将用户的一系列命令记录下来,将记录下来的一组命令作为一个宏。通过宏记录能够实现对玩家所有操作的录像。
GM 指令一般来说能够模拟玩家操作来快速获得游戏的一些资源或者推进游戏进度。如果为玩家操作的命令类型实现一个 toScript() 方法,将玩家的一个操作直接转换成一个可执行的 GM 指令,那么就可以直接通过宏记录执行 GM 指令回放玩家的操作。关于这个 toScript() 方法稍微再解释一下,一般游戏里面会嵌入脚本引擎,例如 lua ,因此可以方便地将一个操作转化成可执行的 lua 脚本。

3) 网络应用

命令对象可以方便地在网络中进行传输,这样一个一个指令就可以同时在多个机器上运行。例如在移动游戏的PVE战斗中,客户端会先将玩家在战斗中的所有操作记录下来,在战斗结束后将所有操作上传给服务器再重新计算一遍,确保客户端没有作弊。

4) 进度条

将每个需要加载的操作作为命令对象,并给命令对象实现一个加载时间预估的方法,可能使得进度条能够较为精准得反映加载进度。

5) 新手引导

使用命令模式可以实现某些类型新手引导的无缝切入,例如某个新手引导只需要玩家一路点击 next 直到点击确认进入实际的游戏环境。那么可以把这个新手引导作为一个命令对象,在需要展示该引导的时候新建命令对象,让该命令对象处理 next 的交互逻辑与每个引导页的展示逻辑,等到完成的时候,命令对象直接调用传入接收者的执行方法完成转换。


^^ 版权衔接线 vv     全文出处:http://www.cnblogs.com/tangyikejun/p/5931571.html

2、具体案例

笔者实现了一个简单的 TicTacToe 游戏来介绍命令模式以及其撤销重做的变体。 TicTacToe 的基础游戏逻辑参考了 Andrew Arnott 的 Java 实现,在第三节中有相关引用。

1)伪代码

笔者将案例上传在这里: https://git.coding.net/tangyikejun/TicTacToeInCommandPattern.git
README 中有对每个代码文件的基本说明。

2)点评

命令模式在游戏开发中真的十分常用,可以说是不可避免会遇到的一个模式。其撤销、重做变体更是应用广泛,随处可见该模式的身影。希望各位看官能够掌握命令模式。
另一方面该模式的专用性也比较强,在一个游戏项目中,能够抽象成命令的概念并不多,但是一旦遇到了就能比较容易的联想到,是个比较容易识别的模式。

3)评级

游戏中使用频度评级:★★★★☆

三、参考

  1. Game Programming Patterns[via Robert Nystrom] (貌似是本很不错的讲游戏中设计模式的书,美中不足没有中文版,Unity主程大大的日常(阿斌) 正在翻译。在命令模式一节中,作者详细介绍了该模式在游戏角色控制中的应用,并且介绍了撤销重做功能作为命令模式的一个变体该如何实现。)

  2. 游戏开发设计模式之命令模式(unity3d 示例实现)[via wolf96 in CSDN] (博主大概是根据 Game Programming Patterns 写了一个 Unity上的实现,写的没那么详细,但是浅显易懂,也不错。)

  3. Let Your Players Undo Their In-Game Mistakes With the Command Pattern[via Andrew Arnott](使用 Java 实现了井字棋游戏的撤销和重做功能,虽然也是用命令模式,但是实现的方式与 Game Programming Patterns 有一点点不一样,这里使用了一个 Command Manager 来管理命令,内部分别保存 undo 和 redo 的命令栈,而不是只使用一个栈。)

  4. "Command" design pattern for games[](作者提到使用命令模式需要解决的两个实际问题,但是似乎并没有人给出合适的解决方案)

  5. Game programming patterns in Unity with C#[via eriknordeus](同样是利用命令模式来控制用户输入,实现撤销重做的功能。在这本书的例子里,作者把重做作为一条命令来进行执行,并且让命令来管理命令列表。笔者觉得这样的实现方式不大合适,一来耦合度提高了,二来概念上undo、redo与其他命令其实并不是平级关系。)
  6. 游戏编程模式- 再探Command模式[via 仙道菜](游戏编程模式- 再探Command模式 的一个翻译)

  7. 《JAVA与模式》之命令模式[via java_my_life](里面提到一个录音系统的示例,并不是很贴合这个模式,但是里面提到了一点,使用命令模式可以方便得实现复合命令,即宏命令)

  8. 图说设计模式-命令模式[via me115](对命令模式相对介绍的比较详细,示例代码用 C++ 给出)

  9. Command pattern-WiKi(对命令模式的概念以及应用领域做了十分详细的说明,本文的应用部分参考了其中的内容)

转载于:https://www.cnblogs.com/tangyikejun/p/5931571.html

[命令模式]在游戏开发中的应用相关推荐

  1. 命令模式在游戏开发中的应用

    命令模式的描述: 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令 ...

  2. 中介者模式在游戏开发中的应用

    中介者模式: 定义一个接口用来封装一群对象的互动行为.中介者通过移除对象之间引用,来减少它们之间的耦合度,并且能改变它们之间的互动独立性. 意图: 通过中介者来解决对象之间的通信,使一个对象在不需要知 ...

  3. [策略模式]在游戏开发中的应用

    设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样,你就能一次又一次地使用该方案而不必做重复劳动. 设计模式在类间关系这个粒度上给出常见问题的解决方案.属于 ...

  4. 策略模式在游戏开发中的应用

    策略模式 在策略模式中,一个类的行为或者其算法可以在运行时更改.这种类型的设计模式属于行为模式.在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象而改变的Contenxt(上下文对象),策 ...

  5. 为什么在游戏开发中我不喜欢用MVC系列模式了

    为什么在游戏开发中我不喜欢用MVC系列模式了: 1,代码繁冗,当你阅读别人的代码,一个很简单的逻辑,被封装了多次,需要在多个代码文件中索引,阅读效率极低.代码文件分散,一些很简单的逻辑,例如按钮点击, ...

  6. 游戏开发中的策略模式

    游戏开发中的策略模式 博主公司今年的新项目是一个重度养成中度策略的塔防游戏(参考国外的random dice),虽然最后项目算是垮了吧(一测的留存实在太低),但是还是需要总结一下代码(总结才会进步). ...

  7. 游戏开发中常用的设计模式 【game design patterns】

    单例模式(Singleton Pattern):用于确保在游戏中只存在一个实例,例如游戏管理器(Game Manager)或资源管理器(Resource Manager). 工厂模式(Factory ...

  8. MANA框架在wap游戏开发中的应用

    Apache MINA框架 用户 IoService>IoProCessor>IoFilter>IoFilter>IoFilter>IoHandler 从左至右Reads ...

  9. 游戏开发中的人工智能(六):基本路径寻找及航点应用

    接上文:游戏开发中的人工智能(五):以势函数实现移动 本文内容:游戏开发人员使用很多技术在游戏环境中寻找路径.本章要谈几种方法,包括航点应用. 基本路径寻找及航点应用 寻找路径的问题有很多不同类型.没 ...

最新文章

  1. C_Imap 邮件的imap
  2. 非常恶俗地分享一首歌曲(童年·葫芦娃)
  3. JeecgUniapp移动框架 2.0版本发布,一份代码多终端适配
  4. linux删除位于后台的进程组,linux命令(12)-进程与作业管理
  5. JavaScript数据结构——散列表(Hash table,也叫哈希表)
  6. Multimodal —— 看图说话(Image Caption)任务的论文笔记(二)引入attention机制
  7. [JAVA]字符串单词倒转处理前面的空格
  8. Flash Player9.0 跟Flash Player8.0区别
  9. CentOS系统安装FTP服务器
  10. [Linux] sed编辑器
  11. fmea第五版pfmea表格_第五版PFMEA模板(含附属评分准则编写指南全套EXCEL表)
  12. greensock插件下载_使用GreenSock插件轻松制作精美的Web动画
  13. Java FTP 下载文件和文件夹
  14. 数字化经营快速发展,微火专注做智慧数字经营系统解决方案提供商
  15. 如何获取iOS App素材
  16. 学生管理系统(添加、查看、删除、修改学生信息)
  17. wxpy 微信聊天机器人的实现
  18. Python:用tkinter制做一个音乐下载小软件
  19. 堪称神器的5款电脑软件,建议收藏
  20. Android Studio 安卓微信底部界面(带消息红点)代码

热门文章

  1. java注解获取参数_JAVA 自定义注解及参数获取 | 学步园
  2. mac使用eclipse创建java_【Java】Mac上使用Eclipse创建Java项目的一般步骤
  3. ORM框架之Spring Data JPA(三)高级查询---复杂查询
  4. 卡巴2009与word冲突完美解决方案,经测试几十台计算机全部通过
  5. 注册app短信验证平台_怎样挑选网站验证码短信平台?
  6. gnuTLS 提供的 DTLS-API
  7. 你或许不知道SDP 但它能改变IaaS安全现状 - 2017.09.05
  8. PyQt5将ui文件编译为py文件的方法
  9. OpenSSL版本号
  10. [摘抄]隧道尽头的灯