格拉苏蒂手表网站,wordpress 按钮链接,wordpress响应速度太慢,seo优化快速排名概述
行为型设计模式只剩下3个模式了#xff0c;它们分别是#xff1a;命令模式、解释器模式、中介模式。这 3 个设计模式使用频率低、理解难度大#xff0c;只在特定的应用场景下才会用到#xff0c;所以这 3 个设计模式你只需要稍微了解即可。
本章学习其中的命令模式。…概述
行为型设计模式只剩下3个模式了它们分别是命令模式、解释器模式、中介模式。这 3 个设计模式使用频率低、理解难度大只在特定的应用场景下才会用到所以这 3 个设计模式你只需要稍微了解即可。
本章学习其中的命令模式。在学习这个模式的过程中你可能遇到的最大疑惑是感觉命令模式没啥用是一种过度设计有更加简单的设计思路可以替代。所以本章讲解的重点是这个模式的设计意图带你搞清楚到底什么情况下才真正需要使用它。 命令模式的原理解读
命令模式的英文翻译是 Command Design Pattern。在 GoF 的《设计模式》一书中它是这么定义的 The command pattern encapsulates a request as an object, thereby letting us parameterize other objects with different requests, queue or log requests, and support undoable operations. 翻译成中文命令模式将请求命令封装为一个对象这样可以使用不同的请求参数化其他对象将不同的请求注入到其他对象并且能够支持请求命令的排队执行、记录日志、撤销等附加控制功能。
这里再进一步解释下不然还是有点绕口。
落实到编码实现命令模式用的最核心的实现手段是将函数封装成对象。在大部分编程语言中函数没办法作为参数传递给其他函数也没法复制给变量。借助命令模式可以将函数封装成对象。具体来说就是设计一个包含这个函数的类实例化一个对象传来传去这样就可以实现把函数像对象一样使用。从实现的角度来说它类似我们之前讲过的回调。
当我们把函数封装成对象之后对象就可以存储下来方便控制执行。所以命令模式的主要作用和应用场景是用来控制命令的执行比如异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等这才是命令模式能发挥独一无二作用的地方。
命令模式的实战讲解
现在再结合一个具体的例子来解释下。
假设我们正在开发一个类似《QQ 卡丁车》这样的手游。这种游戏本身的复杂度集中在客户端。后端基本上只负责数据比如积分、生命值、装备的更新和查询所以后端逻辑相对于客户端来说要简单很多。
考虑到你可能对游戏开发不熟忙着哩稍微说一些背景知识。
为提高性能我们会把玩家的信息保存在内存中。在游戏进行的过程中只更新内存中的数据游戏结束后再将内存中的数据存档也就是持久化到数据库中。为了降低实现的难度一般来说同一个游戏场景里的玩家会被分配到同一台服务商器上。这样一个玩家拉取同一个游戏场景中的其他玩家信息就不需要跨服务器去查找了实现起来就简单了许多。
一般来说游戏客户端和服务端之间的数据交互是比较频繁的所以为了节省网络连接建立的开销客户端和服务器之间一般采用长连接的方式来通信。通信的格式有很多种比如 Protocol Buffer、JSON、XML甚至可以是自定义格式。不管是什么格式客户端发送给服务器的请求一般都包括两部分内容指令和数据。其中指令也可以称为事件数据是执行这个指令所需的数据。
服务器在接受到客户端的请求之后会解析出指令和数据并且根据指令的不同执行不同的处理逻辑。对于这样的一个业务场景一般有两种架构实现思路。
常用的一种实现思路是利用多线程。一个线程接收请求接收到请求之后启动一个新的线程来处理请求。具体来讲就是同一个一个主线程来接收客户端发来的请求。每当接收到请求后就从一个专门用来处理请求的线程池中捞出一个空闲线程来处理。
另一种实现思路是在一个线程内轮询接受请求和处理请求。这种处理方式不太场景。尽管它无法利用多线程多核处理的优势但是对于 IO 密集型的业务来说它避免了多线程不停切换对性能的损耗并且克服了多线程编程 Bug 比较难调试的缺点也算式手游后端服务器开发中比较常见的架构模式了。
接下来就重点讲解下第二种实现方式。
整个手游后端服务器轮询获取客户端发来的请求获取到请求之后借助命令模式把请求包含的数据和处理逻辑封装为命令对象并存储在内存队列中。然后再从队列中取出一定数量的命令来执行。执行完后再重新开始新的一轮轮询。具体代码如下所示。
public interface Command {void execute();
}public class GotDiamondCommand implements Command {// 省略成员变量public GotDiamondCommand(/*数据*/) {// ...}Overridepublic void execute() {// 执行相应逻辑}
}public class GotStartCommand implements Command {// 省略成员变量public GotStartCommand(/*数据*/) {// ...}Overridepublic void execute() {// 执行相应逻辑}
}public class HitObstacleCommand implements Command {// 省略成员变量public HitObstacleCommand(/*数据*/) {// ...}Overridepublic void execute() {// 执行相应逻辑}
}public class ArchiveCommand implements Command {// 省略成员变量public ArchiveCommand(/*数据*/) {// ...}Overridepublic void execute() {// 执行相应逻辑}
}public class GameApplication {private static final int MAX_HANDLED_REQ_COUNT_REP_LOOP 100;private QueueCommand queue new LinkedList();public void mainLoop() {while (true) {ListRequest requests new ArrayList();// 省略从epoll或者select中获取数据并封装成Request的逻辑// 注意设置超时时间如果很长时间没有收到请求就继续下面的逻辑for (Request request : requests) {Event event request.getEvent();Command command null;if (event.equals(Event.GOT_DIAMOND)) {command new GotDiamondCommand(/*数据*/);} else if (event.equals(Event.GOT_STAR)) {command new GotStartCommand(/*数据*/);} else if (event.equals(Event.HIT_OBSTACLE)) {command new HitObstacleCommand(/*数据*/);} else if (event.equals(Event.ARCHIVE)) {command new ArchiveCommand(/*数据*/);} // 一堆else ifqueue.add(command);}int handledCount 0;while (handledCount MAX_HANDLED_REQ_COUNT_REP_LOOP) {if (queue.isEmpty()) {break;}Command command queue.poll();command.execute();}}}
}命令模式 VS 策略模式
看了上面的讲解你可能会觉得命令模式跟策略模式、工长模式非常相似它们的区别在哪里呢另外你可能会感觉学过的很多设计模式都很相似。
实际上每个设计模式都应该由两部分组成第一部分是应用场景即这个模式可以解决哪类问题第二部分是解决方案即这个设计模式的设计思路和代码实现。不过代码实现并不是模式必须包含的。如果你只是单纯的关注解决方案这一部分甚至只关注代码实现就会产生大部分设计模式都很相似的错觉。
实际上设计模式之间的主要区别在于设计意图也就是应用场景。单纯地看设计思路或代码实现有些模式确实很相似比如策略模式和工厂模式。
之前讲策略模式的时候有讲到过策略模式包含策略的定义、创建和使用三个部分从代码结构上来看它非常像工厂模式。它们的区别在于策略模式更注重 “策略” 或 “算法” 这个特定的应用场景用来解决根据运行时状态从一组策略中选择不同策略的问题而工厂模式侧重封装对象的创建过程这里的对象没有任何业务场景的限定可以是策略但也可以是其他东西。从设计意图上看这两个模式完全是两回事。
接下来再看看命令模式和策略模式的区别。你可能会觉得命令的执行逻辑页可以看做策略那它是不是就是策略模式了呢实际上这两种有一点细微的区别。
在策略模式中不同的策略具有相同的目的、不同的实现、互相之间可以替换。比如BubbleSort、SelectionSort 都是为了实现排序只不过一个是用冒泡算法来实现另一个是用选择排序算法来实现。而在命令模式中不同的命令具有不同的目的对应不同的处理逻辑并且互相不可替换。
总结
命令模式在平时开发中并不常用你稍微了解即可。
落实到编码实现命令模式用到最核心的实现手段就是将函数封装成对象。我们知道在大部分编程语言中函数是没法作为参数传递给其他函数的也没法赋值给变量。借助命令模式我们将函数封装成对象这样就可以实现把函数像对象一样使用。
命令模式的主要作用和应用场景是用来控制命令的执行比如异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等这才是命令模式能发挥独一无二作用的地方。