命令模式
GOF中对命令模式的描述如下:
将一个请求封装为一个对象 ,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
这里的请求就相当于一个命令的调用。命令模式的核心就是解耦命令调用者和具体的命令执行者之间的关系。
前面说过命令模式是回调机制的面向对象版本。命令模式将要执行的动作抽象出来,然后将具体的动作对象以参数的形式传递进来。
一个简单的命令模式的代码如下所示:
public interface Command{
public void execute();
}
public class CommandOne implements Command{
public void execute(){
// execution code...
}
}
public class CommandTwo implements Command{
public void execute(){
// execution code...
}
}
public class Invoker{
Command one;
Command two;
public void doActionOne(){
one.execute();
}
public void doActionTwo(){
two.execute();
}
}
// 客户程序调用invoker对象执行命令
public class Client{
public static void main(String[] args){
Invoker invoker = new Invoker();
invoker.doActionOne();
invoker.doActionTwo():
}
}
这里的Invoker类就是新增的用于解耦命令调用者和命令执行者之间关系的类,调用程序不再直接依赖于命令对象,这其实也就是在两者之间加入了一个中间层,将原来两者之间的直接耦合关系转换为了对中间层的依赖关系。
这里只是一个简单的演示,在GOF的描述中命令模式的作用还包括了“对请求排队或记录请求日志,以及支持可撤消的操作”。这里说的是命令模式另一方面的优点:时间上的解耦 。即先将要执行的命令对象置入到一个命令队列中,根据业务规则在以后的某一指定时刻再执行此命令。一段示例的代码如下:
public interface Command{
public void ido();
public void undo();
public void redo();
}
public class CommandOne implements Command{
public void ido(){
// execution code...
}
// 省略undo 和 redo操作的实现
}
public class CommandTwo implements Command{
public void ido(){
// execution code...
}
// 省略undo 和 redo操作的实现
}
public class Invoker{
private List commands;
public void setCommands(List commands){
this.commands = commands;
}
public void addCommand(Command command, int index){
this.commands.add(index, command);
}
public void removeCommand(int index){
this.commands.remove(index);
}
public void ido(){
for(Command command : commands){
command.ido();
}
}
// redo和undo的操作与ido类似
}
用组合模式来替代命令模式
在上面的代码中,我们是以一致的方式对待每一个命令 。如果应用中存在这种前提的话,可以采用组合模式来代替命令模式。将命令队列组合成一个组合对象,从而将请求对象和命令对象之间的一对多关系转换为了一对一关系。