开局还是那种图,各位客官往下看...
张无忌学太极拳,遗记了所有招式,打倒了"玄冥二老",所谓"心中无招"。设计模式堪称招数,如果先学通了各种模式,又忘掉了所有模式而得心应手,堪称OO之最高境界。
命令模式是什么?
在面向对象程式设计的领域中,命令模式(Command Pattern)是一种设计模式,它尝试以物件来代表实际行动。
命令模式是一种行为型模式,它将申请以命令的模式包裹在对象外面,传递给调用对象,调用对象寻找匹配该命令的对象,将命令给该对象执行。也就是分为了三步:
- 1、命令被包裹在申请对象里,传递给调用对象。
- 2、调用对象查找匹配该命令(能够解决该命令)的对象,将该命令传递给匹配的对象。
- 3、该对象执行传递给它的命令。
一般而言,在软件开发中,行为的请求者和行为的执行者是严密耦合在一起的,调用关系简略易懂,然而这样不容易拓展,有些时候,咱们须要记录、撤销、重做解决的时候,不易批改。因而咱们须要将命令抽象化,封装起来,不间接调用真正的执行者办法,易于拓展。
举个事实中的例子,比方咱们去餐厅吃饭:
点餐(写好菜单,发动申请) --> 订单零碎解决,生成订单(创立命令) --> 厨师获取到订单,开始做菜(执行命令)
,在这个过程中咱们并没有间接与厨师交谈,不晓得那个厨师做,厨师也不晓得是哪个顾客须要,只须要依照订单解决就能够。
又比方,咱们常常应用智能音响,我常常叫它 ”小度小度,帮我关上空调“,”小度小度,帮我关上窗帘“等等,在整个过程中,我收回命令 --> 小度承受到命令,包装成为申请 --> 让真正接管命令的对象解决(空调或者窗帘控制器)
,我没有手动去操作空调和窗帘,小度也能够承受各种各样的命令,只有接入它,我都通过它去操作。
命令模式中的角色
在命令模式外面,一共存在以下的角色:
Command
(形象命令):命令有通用的个性,将命令形象成一个类,不同的命令做不同的实现ConcreteCommand
(具体命令类):实现形象命令,做具体的实现Receiver
(接受者):真正执行命令的对象Invoker
(调用者/请求者):申请的封装发送者,它通过命令对象来执行申请,不会间接操作接受者,而是间接关联命令对象,间接调用到接受者的相干操作。Client
(客户端):个别咱们在客户端中创立调用者对象,具体的命令类,去执行命令。
命令模式的UML
图如下:
命令模式的实现
上面咱们模仿一下智能音响的场景:
先创立一个空调对象,也就是Receiver
(接受者),它才是真正的操作对象:
public class AirConditionerReceiver { public void turnOn(){ System.out.println("关上空调..."); } public void turnOff(){ System.out.println("敞开空调..."); }}
形象命令类如下:
public interface Command { void execute();}
关上TurnOnCommand
以及敞开TurnOffCommand
空调的具体实现类:
public class TurnOnCommand implements Command{ private AirConditionerReceiver airConditionerReceiver; public TurnOnCommand(AirConditionerReceiver airConditionerReceiver) { super(); this.airConditionerReceiver = airConditionerReceiver; } @Override public void execute() { airConditionerReceiver.turnOn(); }}
public class TurnOffCommand implements Command{ private AirConditionerReceiver airConditionerReceiver; public TurnOffCommand(AirConditionerReceiver airConditionerReceiver) { super(); this.airConditionerReceiver = airConditionerReceiver; } @Override public void execute() { airConditionerReceiver.turnOff(); }}
Invoker
调用者,/请求者(智能音响):
public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void action(){ System.out.print("小度智能家居为你服务 --> "); command.execute(); }}
客户端测试一下:
public class Client { public static void main(String[] args) { Command command = new TurnOnCommand(new AirConditionerReceiver()); Invoker invoker = new Invoker(command); invoker.action(); Command turnOffCommand = new TurnOffCommand(new AirConditionerReceiver()); Invoker turnOff = new Invoker(turnOffCommand); turnOff.action(); }}
测试后果如下:
小度智能家居为你服务 --> 关上空调...小度智能家居为你服务 --> 敞开空调...
通过以上的测试,咱们的确通过命令传递,就能够操作空调,客户端也没有间接关联空调,如果须要其余操作,那么另外实现一个命令实现类即可,拓展比拟不便,不同命令之间不会相互影响。
命令模式的拓展
- 多条命令
如果咱们须要执行多条命令,那么能够思考在外部保护一个列表,增加之后顺次执行即可。
- 保护日志
如果思考到执行命令的日志,咱们则须要将对象序列化保存起来(磁盘上),保护好执行的状态,在系统故障的时候,能够从断开的中央继续执行。
- 撤销
如果某个命令须要撤销,那么咱们须要在命令的抽象类外面加一个undo()
办法,相似于Mysql
数据库的undo
操作,执行它即可撤销操作,当然这个两头过程波及到了状态的保护,细节须要具体的命令来实现。(相似于数据库的事务回滚)
优缺点
长处:
- 升高零碎耦合度
- 易于拓展新的命令
毛病:
- 具体命令如果过多,类数量爆炸
命令模式次要是想让请求者与真正的接受者解耦合,其实用的手腕也是加一层(命令层)的操作,有一句话说得好,不是我说的:
计算机科学畛域的任何问题都能够通过减少一个间接的中间层来解决。
这句话简直概括了计算机软件体系结构的设计要点.整个体系从上到下都是依照严格的层级结构设计的,体现了设计的层次感,而不是互相缠绕。集体感觉之所以这样设计,最基本的起因在于社会分工以及人类大脑思维对于分层体系认知能力比拟强,毕竟代码是不同人写给不同人读的。
【作者简介】:
秦怀,公众号【秦怀杂货店】作者,集体网站:http://aphysia.cn,技术之路不在一时,山高水长,纵使迟缓,驰而不息。
剑指Offer全副题解PDF
开源编程笔记
设计模式系列:
- 设计模式【1】-- 单例模式到底几种写法?
- 设计模式【1.1】-- 你想如何毁坏单例模式?
- 设计模式【1.2】-- 枚举式单例有那么好用么?
- 设计模式【1.3】-- 为什么饿汉式单例是线程平安的?
- 设计模式【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】-- 模板模式怎么弄?