举个栗子
指挥官向士兵下达命令,士兵执行
实现代码如下:
class Soldier { public void exe() { System.out.println("执行命令"); }}class Commander { public void invok() { Soldier soldier=new Soldier(); soldier.exe(); }}
代码问题
上诉代码是最基本的一个实现,存在问题:
- Commander和Soldier高度耦合
- 新增命令的话,要改动Commander类,扩展性不好(影响已有实现),不符合OCP原则
- 指挥官指挥实现多条命令时,又要改Commander
- 士兵执行命令时如果加一些控制的话,如记录日志、延缓执行,加到哪都不合适,SRP和OCP原则。
重构后代码
class Soldier { public void doCommandA() { System.out.println("执行命令A"); } public void doCommandB() { System.out.println("执行命令B"); }}class CommandCenterA implements Command{ Soldier soldier; public CommandCenterA(Soldier soldier) { this.soldier=soldier; } @Override public void exe() { waitTime(); soldier.doCommandA(); soldier.doCommandB(); } private void waitTime() { System.out.println("延迟执行"); } }class Commander { Command command; public Commander(Command command) { this.command=command; } public void exe(){ command.exe(); }}class Client{public static void main(String[] args) { Soldier soldier=new Soldier(); Command command=new CommandCenterA(soldier);//将soldier注入到命令中心 Commander commander=new Commander(command);//将命令中心注入到指挥官 commander.exe();}
解决的问题
- Commander和Soldier隔离,解除耦合,
- 新增命令时,只需新增Command接口的实现CommandCenter,实现对命令和请求控制
- CommandCenter可以实现复合命令,延迟执行,记录日志等
命令模式
命令模式把一个请求或者操作封装到一个对象中,并把发出命令和执行命令隔离,使得发出命令不必关心命令如何执行。
讲个实例:
比如开关灯和开关空调。 最原始的,就是把两根电线连到一起,灯亮空调开,断开,灯灭空调关。(Receiver) 现在我们加了个开关,开关不仅能开灯,还能开空调。(将电灯开关和空调开关进一步抽象) 开关内部的实现,就是我们的命令中心。(开空调时可以设置温度,开灯时可以延缓执行) 将开关和电线隔离,并加入了我们对命令的具体控制。这就是命令模式。Java实现要点 Invoker(请求者)+Commander(命令中心)+Receiver(执行者)
- 将请求者和执行者,加入中间层“命令中心”,将请求者对象绑定于一个动作
- 将命令中心抽象出接口,使得请求者依赖于接口而不是具体实现
- 命令中心实现对请求者和执行者的解耦
JDK中的命令模式
比较经典的应该就是Runnable了吧。
//执行者Runnable soldier= new Runnable() { public void run() { System.out.println("执行命令"); }};
//命令中心Runnable thread=new Thread(solder);//可继承Thread继续定制thread.sleep(1000);
//请求者thread.start();
Thread源码:
/* What will be run. */private Runnable target;public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0);}
/** * If this thread was constructed using a separate *Runnable
run object, then that *Runnable
object'srun
method is called; * otherwise, this method does nothing and returns. ** Subclasses of
Thread
should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */@Overridepublic void run() { if (target != null) { target.run(); }}
注入了Runnable,并实现了对Runnable的控制。
优点
- 松耦合
- “命令中心”对命令可控(如日志化,延缓,复合命令),对请求可控(如队列,参数化)
- 扩展性。只需要实现新的“命令中心”即可,任意装配,并且不影响已有的实现,因为命令发起者(指挥官)中的命令中心时接口注入。