首页 > 技术文章 > 十一个行为模式之命令模式(Command Pattern)

zhangfei614 2016-11-17 13:56 原文

定义:
将一个请求封装成对象,使得请求发送者和请求接受者之间相互隔离,消除两者之间的耦合。引入命令类,使得不同请求对客户参数化,并且可以对命令添加附件操作,如:排队、撤销、日志、组合等。

结构图:

  • Command:抽象命令类,一般是一个抽象类或者接口。在其中定义了命令的执行execute()、undo()等操作。
  • ConcreteCommand:具体命令类,实现了抽象命令类的方法,并且持有命令接受者的引用。具体执行方法时,调用接受者的相关操作。
  • Invoker:请求发送者,通过命令对象执行请求。针对抽象命令类编程,并不需要关心对应的命令如何执行,被谁执行。与抽象命令的关联关系也不固定,可以通过注入或者构造的方法或者采用XML和反射的方法来进行关联。
  • Reciver:请求接受者,执行请求的相关操作,对请求进行详细的业务处理。

命令队列
当一个请求需要将需要多个接受者进行处理的时候,可以将多个命令放入队列中,每个命令对应一个接受者。请求发送者执行请求时,将遍历请求队列,对每个命令执行操作。

class CommandQueue {  
    //定义一个ArrayList来存储命令队列  
    private ArrayList<Command> commands = new ArrayList<Command>();  

    public void addCommand(Command command) {  
        commands.add(command);  
    }  

    public void removeCommand(Command command) {  
        commands.remove(command);  
    }  

    //循环调用每一个命令对象的execute()方法  
    public void execute() {  
        for (Object command : commands) {  
            ((Command)command).execute();  
        }  
    }  
}
class Invoker {  
    private CommandQueue commandQueue; //维持一个CommandQueue对象的引用  

    //构造注入  
    public Invoker(CommandQueue commandQueue) {  
        this. commandQueue = commandQueue;  
    }  

    //设值注入  
    public void setCommandQueue(CommandQueue commandQueue) {  
        this.commandQueue = commandQueue;  
    }  

    //调用CommandQueue类的execute()方法  
    public void call() {  
        commandQueue.execute();  
    }  
}

命令的撤销
在抽象命令中不仅定义excute()接口,也定义undo()接口。所有具体执行的命令需要实现undo操作,可以结合备忘录模式来记录历史状态,完成该撤销操作。

//抽象命令类  
abstract class AbstractCommand {  
    public abstract int execute(); //声明命令执行方法execute()  
    public abstract int undo(); //声明撤销方法undo()  
}  

宏命令
宏命令又称作组合命令,可以看做命令模式与组合模式的联合。对于宏命令可以拥有一个命令集合,当具体执行的时候需要遍历集合中的所有命令来递归地执行操作。

优点:

  • 将请求发送者和接受者之间完全解耦,使两者都具有很好的独立性。相同的请求者可以对应不同的接受者,而相同的接受者可以供不同请求者使用。
  • 可以很方便地添加新的命令,无需修改源码,可以通过配置文件制定。
  • 可以对命令添加很对其它的附加操作,例如:队列、日志、宏命令等,更好地符合业务需求。

实例:

CommandPattern

推荐阅读