命令模式与适配器模式,谁容易理解?
命令模式针对(任意类型的)单一的方法,函数接口Command大吼一声:向我开炮。
向我适配
风烟滚滚唱英雄……所有消息接收者/ Receiver的方法被一个个的被匹配成目标角色execute ()。
Invoker/ Receiver关注服务请求,它遵循对依赖关系泛泛而谈的Client/Server结构,Invoker依赖于Receiver。本节从源代码上探讨解耦Invoker/ Receiver。
1.无视被调的方法名和消息接收者
如果Invoker希望无视被调的方法名如Receiver.m()和m1(),显然需要某个众所周知的、一般性的方法名,例如execute ()、run()、go()等对目标方法进行间接的调用。如:
publicvoid execute (Receiver r){
r.m();
}
而这种间接调用,不应该在Receiver的类体中编写。否则execute()间接调用m(),execute1()间接调用m1(),就相当于改变了方法名。为了间接调用,需要设计一个类X。假设X知道消息接收者是谁,即execute (Receiver)所需要的参数X自己搞定,则Invoker将不知道Receiver为何物。
package method.command.get;
public class Receiver {
public void m(){ System.out.println("Receiver.m()"); }
public void m1(){ System.out.println("Receiver.m1()"); }
}
package method.command.get;
public class X{
private Receiver r = new Receiver();
public void execute(){
r.m();
}
}// X1 略,其execute() 中调用r.m1();
package method.command.get;
public class Invoker{
public static void test1() {
new X().execute();
// //比较通常的直接调用
// Receiver r = new Receiver();
// r.m();
}
}
因为Receiver有方法m()、m1()或更多,需要设计类似X的X1、X2封装m1()、m2(),它们用execute ()或go()对目标方法进行间接的调用。统一地,这里使用execute ()。
2. Command接口
自然而然地,可以将X、X1等类泛化,得到它们的父类型Command。例程 3-15泛化
package method.command.get;
public interface Command{
public void execute();
}// public class X implements Command,略
package method.command.get;
public class Invoker{
public static void test(){
Command c = (Command)tool.God.create("3-15-Command");
c.execute();
c = (Command)tool.God.create("3-15-Command1");
c.execute();
}
}
于是,在Command的实现类确定消息接受者时,获得如下结构。
★函数接口Command是一个一统江湖式的、关注一个操作的适配器模式的目标角色,完成消息发出者与执行者(Invoker/ Receiver)的解耦。
3. 命令模式的角色
命令模式的简化结构中包含如下角色:
①Command。命令(即接口Command)封装一个普适方法如execute()。
②具体命令(如X),将调用消息接受者的相应操作。
③Invoker,在通常的演示程序中,它发布命令并要求它执行。它可以下达的一系列具体命令,也可以将系列具体命令组合成一个队列、可以组合成一个批命令;
④接受者/ Receiver。具体命令如X,通过依赖注入X(Receiver)可以绑定任意子类型的接受者。各种具体命令的接受者可以不同,接受者可以具有自己的类层次。
注:[GoF]中的Client角色稍后说明。
续-命令与执行