1:命令模式的本质
命令模式的本质:封装请求 。
前面讲了,命令模式的关键就是把请求封装成为命令对象,然后就可以对这个对象进行一系列的处理了,比如上面讲到的参数化配置、可撤销操作、宏命令、队列请求、日志请求等功能处理。
2:何时选用命令模式
建议在如下情况中,选用命令模式:
在领会了命令模式本质后,来思考一个命令模式退化的情况。
前面讲到了智能命令,如果命令的实现对象超级智能,实现了命令所要求的功能,那么就不需要接收者了,既然没有了接收者,那么也就不需要组装者了。
(1)举个最简单的示例来说明
比如现在要实现一个打印服务,由于非常简单,所以基本上就没有什么讲述,依次来看,命令接口定义如下:
public interface Command { public void execute(); }
命令的实现示例代码如下:
public class PrintService implements Command{ /** * 要输出的内容 */ private String str = ""; /** * 构造方法,传入要输出的内容 * @param s 要输出的内容 */ public PrintService(String s){ str = s; } public void execute() { //智能的体现,自己知道怎么实现命令所要求的功能,并真的实现了相应的功能,不再转调接收者了 System.out.println("打印的内容为="+str); } }
此时的Invoker示例代码如下:
public class Invoker { /** * 持有命令对象 */ private Command cmd = null; /** * 设置命令对象 * @param cmd 命令对象 */ public void setCmd(Command cmd){ this.cmd = cmd; } /** * 开始打印 */ public void startPrint(){ //执行命令的功能 this.cmd.execute(); } }
最后看看客户端的代码,示例如下:
public class Client { public static void main(String[] args) { //准备要发出的命令 Command cmd = new PrintService("退化的命令模式示例"); //设置命令给持有者 Invoker invoker = new Invoker(); invoker.setCmd(cmd); //按下按钮,真正启动执行命令 invoker.startPrint(); } }
测试结果如下:
打印的内容为=退化的命令模式示例
(2)继续变化
如果此时继续变化,Invoker也开始变得智能化,在Invoker的startPrint方法里面,Invoker加入了一些实现,同时 Invoker对持有命令也有意见,觉得自己是个傀儡,要求改变一下,直接在调用方法的时候传递命令对象进来,示例代码如下:
public class Invoker { public void startPrint(Command cmd){ System.out.println("在Invoker中,输出服务前"); cmd.execute(); System.out.println("输出服务结束"); } }
看起来Invoker退化成一个方法了。
这个时候Invoker很高兴,宣称自己是一个智能的服务,不再是一个傻傻的转调者,而是有自己功能的服务了。这个时候Invoker调用命令对象的执行 方法,也不叫转调,改名叫“回调”,意思是在我Invoker需要的时候,会回调你命令对象,命令对象你就乖乖的写好实现,等我“回调”你就可以了。
事实上这个时候的命令模式的实现,基本上就等同于Java回调机制的实现,可能有些朋友看起来感觉还不是佷像,那是因为在Java回调机制的常见实现上,经常没有单独的接口实现类,而是采用匿名内部类的方式来实现的。
(3)再进一步
把单独实现命令接口的类改成用匿名内部类实现,这个时候就只剩下命令的接口、Invoker类,还有客户端了。
为了使用匿名内部类,还要设置要输出的值,对命令接口做点小改动,增加一个设置输出值的方法,示例代码如下:
public interface Command { public void execute(); /** * 设置要输出的内容 * @param s 要输出的内容 */ public void setStr(String s); }
此时Invoker就是上面那个,而客户端会有些改变,客户端的示例代码如下:
public class Client { public static void main(String[] args) { //准备要发出的命令,没有具体实现类了 //匿名内部类来实现命令 Command cmd = new Command(){ private String str = ""; public void setStr(String s){ str = s; } public void execute() { System.out.println("打印的内容为="+str); } }; cmd.setStr("退化的命令模式类似于Java回调的示例"); //这个时候的Invoker或许该称为服务了 Invoker invoker = new Invoker(); //按下按钮,真正启动执行命令 invoker.startPrint(cmd); } }
运行测试一下,结果如下:
在Invoker中,输出服务前 打印的内容为=退化的命令模式类似于Java回调的示例 输出服务结束
(4)现在是不是看出来了,这个时候的命令模式的实现,基本上就等同于Java回调机制的实现。这也是很多人大谈特谈命令模式可以实现Java回调的意思。
当然更狠的是连Invoker也不要了,直接把那个方法搬到Client中,那样测试起来就更方便了。在实际开发中,应用命令模式来实现回调机制的时 候,Invoker通常还是有的,但可以智能化实现,更准确的说Invoker充当客户调用的服务实现,而回调的方法只是实现服务功能中的一个或者几个步 骤。
命令模式结束,谢谢您的捧场,鞠躬ing!!!
转载自:http://chjavach.iteye.com/blog/719371