命令模式

命令模式是一种高内聚的模式,定义为:将一个请求封装为一个对象,从而使不同的请求把客户端参数化,将请求排队或记录请求日志,可以提供命令的撤销和恢复功能。

命令模式通常有三个角色:

  • Receiver接收者角色。接收到命令后执行具体任务
  • Command命令角色。需要执行的所有命令都在这里定义
  • Invoker调用者角色。接收到命令,并执行命令

下面看一段通用代码:

//接收者,可以是多个,所以定义为抽象类
public abstract class Receiver{
    //抽象接收者,定义每个接收者必须完成的任务
    public abstract void doSomething();
}
//具体的接收者
public class ConcreateReceiver1 extends Receiver{
    //处理逻辑
    public void doSomething(){}
}
public class ConcreateReceiver2 extends Receiver{
    //处理逻辑
    public void doSomething(){}
}
//抽象的Command类
public abstract class Command{
    //每个命令类都必须有一个执行命令的方法
    public abstract void excute();
}
//具体的Command类,通过构造函数确定是针对哪个接收者发出的命令
public class ConcreateCommand1 extends Command{
    //对哪个receiver类进行命令处理
    private Receiver receiver;
    //构造函数接收者
    public ConcreateCommand1(Receiver receiver){
        this.receiver = receiver;
    }
    //必须实现一个命令
    public void excute(){
        this.receiver.doSomething();
    }
}
public class ConcreateCommand2 extends Command{
    //对哪个receiver进行命令处理
    private Receiver receiver;
    public ConcreateCommand2(Receiver receiver){
        this.receiver = receiver;
    }
    //必须实现一个命令
    public void excute(){
        this.receiver.doSomething();
    }
}
//调用者类,仅实现命令的传递
public class Invoker{
    private  Command command;
    //受气包,接收命令
    pubulic void setCommand(Command command){
        this.command = command;
    }
    //执行命令
    public void action(){
        this.command.excute();
    }
}
//场景类
public class Client{
    public static void main(String[] args){
        //首先声明调用者
        Invoker invoker = new Invoker();
        //定义接收者
        Receiver receiver = new ConcreateReceiver1();
        //定义命令,指定接收者
        Command command = new ConcreateCommand(receiver);
        //把命令交给调用者执行
        invoker.setCommand(command);
        invoker.action();
    }
}

命令模式的优点:

  • 类间解耦。调用者和接收者没有任何依赖关系,调用者只需要调用Command抽象类的excute方法就可以,不需要了解是哪个接收者执行
  • 可扩展性。Command的子类非常容易扩展,而调用者不会和更高层模块耦合
  • 可以结合其他模式取得更好的表现。和责任链模式组合实现命令族解析任务;和模板方法模式组合减少Command子类膨胀问题

命令模式缺点:

  使用不当,会产生command子类膨胀的问题。

应用场景:

  所有你认为是命令的地方都可以使用。比如GUI的点击任务,DOS窗口的模拟命令等。

最佳实践:

  在通用示例中,Receiver角色暴露给了Client类!这是不应该存在的依赖,实际应用中,receiver模块一般会被封装掉(除非必要,比如有撤销处理),下面展示优化的例子:

public abstract class Command {
    //定义一个子类的全局共享变量
    protected final Receiver receiver;
    //实现类必须定义一个接收者
    public Command(Receiver _receiver){
        this.receiver = _receiver;
    }
    //每个命令类都必须有一个执行命令的方法
    public abstract void execute();
}    
public class ConcreteCommand1 extends Command {
    //声明自己的默认接收者
    public ConcreteCommand1(){
        super(new ConcreteReciver1());
    }
    //设置新的接收者
    public ConcreteCommand1(Receiver _receiver){
        super(_receiver);
     }
    //每个具体的命令都必须实现一个命令
    public void execute() {
        //业务处理
        super.receiver.doSomething();
    }
}
public class ConcreteCommand2 extends Command {
    //声明自己的默认接收者
    public ConcreteCommand2(){
        super(new ConcreteReciver2());
    }
    //设置新的接收者
    public ConcreteCommand2(Receiver _receiver){
        super(_receiver);
    }
    //每个具体的命令都必须实现一个命令
    public void execute() {
        //业务处理
        super.receiver.doSomething();
    }
}    
public class Client {
    public static void main(String[] args) {
    //首先声明调用者Invoker
    Invoker invoker = new Invoker();
    //定义一个发送给接收者的命令
    Command command = new ConcreteCommand1();
    //把命令交给调用者去执行
    invoker.setCommand(command);
    invoker.action();
    }
}
原文地址:https://www.cnblogs.com/loveBolin/p/9716120.html