设计模式【14】--从智能音箱学习命令模式所谓“心无旁骛”。设计模式可以说是技巧。如果先学会各种模式,忘掉所有模式,随心所欲,可谓OO的最高境界。什么是命令模式?在面向对象编程领域,命令模式(CommandPattern)是一种试图用对象来表示实际动作的设计模式。命令模式是一种行为模式。它以命令的形式包装请求并将其传递给调用对象。调用对象找到与命令匹配的对象,并对该对象执行命令。也就是分为三个步骤:1.命令被包裹在request对象中,传递给调用对象。2.调用对象寻找匹配命令的对象(可以处理命令),并将命令传递给匹配的对象。3.对象执行传递给它的命令。一般来说,在软件开发中,行为的请求者和行为的执行者是紧耦合在一起的,调用关系简单易懂,但不易扩展。有时,我们需要记录、撤销、重做处理时间,不容易修改。因此,我们需要对命令进行抽象和封装,而不是直接调用真正的executor方法,便于扩展。举个现实中的例子,比如我们去饭店吃饭:点餐(写菜单,发起请求)-->点餐系统处理,生成订单(createcommand)-->厨师拿到点菜开始做菜(执行命令),这个过程我们没有直接和厨师对话,我们不知道是哪位厨师做的,厨师也不知道是哪个顾客需要的,我们只需要处理它按照顺序。再比如,我们经常用的智能音箱,我经常叫它“小度小度,帮我开空调”、“小度小度,帮我拉窗帘”等等。整个过程中,我发出命令-->小度收到命令,打包成请求-->让实际收到命令的对象去处理(空调或窗帘控制器),我没有手动操作空调还有窗帘,小度也可以接受各种订单,只要收到我输入,我通过它操作。命令模式中的角色在命令模式中,有以下几种角色:Command(抽象命令):命令具有通用的特性,将命令抽象成一个类,不同的命令有不同的实现方式。ConcreteCommand(具体命令类):实现抽象命令,做具体实现Receiver(接收者):实际执行命令的对象直接关联命令对象,间接调用接收者的相关操作。Client(客户端):一般我们在客户端创建一个调用者对象,一个具体的命令类,来执行命令。命令模式的UML图如下:命令模式的实现我们来模拟一下智能音响的场景:首先创建一个空调对象,即Receiver(接收器),这是真正的操作对象:public类AirConditionerReceiver{publicvoidturnOn(){System.out.println("打开空调...");}publicvoidturnOff(){System.out.println("关空调...");}}抽象命令类如下:publicTurnOnCommand(AirConditionerReceiverairConditionerReceiver){super();this.airConditionerReceiver=airConditionerReceiver;}@Overridepublicvoidexecute(){airConditionerReceiver.turnOn();}}公共类TurnOffCommand实现命令{privateAirConditionerReceiverairConditionerReceiver;publicTurnOffCommand(AirConditionerReceiverairConditionerReceiver){super();河;}@Overridepublicvoidexecute(){airConditionerReceiver.turnOff();}}Invokercaller,/requester(智能音频):publicclassInvoker{privateCommandcommand;公共调用者(命令命令){this.command=command;}publicvoidaction(){System.out.print("小都智能家居为您服务-->");命令.执行();}}客户端测试:publicclassClient{publicstaticvoidmain(String[]args){Commandcommand=newTurnOnCommand(newAirConditionerReceiver());调用者invoker=newInvoker(command);调用者.action();命令turnOffCommand=newTurnOffCommand(newAirConditionerReceiver());调用者turnOff=newInvoker(turnOffCommand);关闭动作();}}测试结果如下:小度智能为您服务-->打开空调...小度智能为您服务-->关闭空调...通过以上测试,我们可以操作空调通过命令传输,客户端与空调没有直接关系。如果需要其他操作,那么可以实现另一个命令实现类。扩展起来更方便,不同的命令不会互相影响。命令方式展开多条命令如果我们需要执行多条命令,可以考虑在内部维护一个列表,添加后依次执行。维护日志如果我们考虑执行命令的日志,我们需要将对象序列化并保存(在磁盘上),维护执行状态,并在系统出现故障时从断开连接的地方继续执行。Undo如果一个命令需要被撤销,那么我们需要在该命令的抽象类中添加一个undo()方法,类似于Mysql数据库的撤销操作。执行它可以撤销操作。当然,这个中间过程涉及到状态维护,具体需要具体的命令来实现。(类似于数据库事务回滚)优缺点优点:降低系统耦合,方便扩展新命令缺点:如果具体命令过多,类数会爆炸。命令模式主要是想把请求者和真正的接收者解耦。实用的trick也是加一层(命令层)操作。有句话说得好,不是我的:计算机科学领域的任何问题都可以通过增加一个间接中间层来解决。这句话几乎概括了计算机软件体系结构的设计要点。整个系统按照从上到下严格的层级结构设计,体现了设计的层次感,而不是相互交织。个人认为,这种设计的根本原因在于社会分工和人脑对等级制度比较强的认知能力。毕竟,代码是不同的人写的,供不同的人阅读。【作者简介】:公众号【秦淮杂货铺】作者秦淮,个人网站:http://aphysia.cn,技术之路非一蹴而就,山高水长江河漫漫,纵然缓慢,也不会停下脚步。剑指一问一答PDF开源编程笔记设计模式系列:设计模式[1]——单例模式有几种写法?设计模式【1.1】——你想如何打破单例模式?设计模式【1.2】--枚举单例这么好用?设计模式[1.3]--Hungry式单例为什么是线程安全的?设计模式[2]--看简单工厂模式?设计模式[2.1]--简单工厂模式是如何演变成工厂方法模式的?设计模式[2.2]--工厂模式是如何演变成抽象工厂模式的?设计模式[3.1]--浅谈代理模式之静态、动态、cglib代理设计模式[3.2]--JDK动态代理源码解析有多香?设计模式[3.3]--CGLIB动态代理源码解释设计模式[4]--建造者模式设计模式详解[5]--原型模式设计模式[6.1]--适配器模式设计模式初探[6.2]]--浅谈适配器模式设计模式[7]--探究桥接模式设计模式[8]--手把手教我写装饰器模式设计模式[9]--外观模式?没那么高大上的设计模式[10]——顺便看看享元模式设计模式[11]——搞定组合模式设计模式[12]——搞定最近流行的策略模式设计模式[13]--模板模式胡同怎么样?
