命令模式

一 定义

命令模式也属于行为型设计模式之一。
定义:将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

所以,命令模式的本质是,封装请求。

二 模式结构

 
 

角色介绍

  • Receiver:接收者角色。
    该类是命令的具体执行者,负责具体实施或者执行一个请求,说的通俗一点,就是真正干活的角色。
  • Command:命令角色
    定义所有的具体命令类的抽象接口。
  • ConcreteCommand:具体命令角色
    该类实现了Command接口
  • Invoker:请求者角色
    该类的职责是调用命令对象执行具体的请求。
  • Client:客户端

通用代码如下

  • 抽象的命令接口
public interface Command {

    /**
     * 执行具体操作的命令
     */
    void execute();
}
  • 接收者类
public class Receiver {

    /**
     * 真正执行具体命令逻辑的方法
     */
    public void action(){
        System.out.println("执行具体的操作");
    }
}
  • 具体的命令类
public class ConcreteCommand implements Command{

    private Receiver mReceiver;

    public ConcreteCommand(Receiver receiver){
        this.mReceiver=receiver;
    }


    @Override
    public void execute() {
        // 调用接收者的相关方法来执行具体逻辑
        mReceiver.action();
    }
}
  • 请求者类
public class Invoker {

    private Command mCommand; // 持有一个对应命令对象的引用

    public Invoker(Command command){
        this.mCommand=command;
    }

    public void action(){
        // 调用具体命令对象的相关方法,执行具体命令
        mCommand.execute();
    }

}
  • 客户端测试代码
        // 构造一个接收者对象
        Receiver receiver=new Receiver();
        // 根据接收者对象构造一个命令对象
        Command command=new ConcreteCommand(receiver);
        // 根据具体的对象构造请求者对象
        Invoker invoker=new Invoker(command);
        // 执行请求方法
        invoker.action();

三 实例

我们以遥控器遥控电视为例,以前的电视是没有遥控器的,你如果想换台的话,要跑到电视机前,手动按换台按键,非常麻烦。现在我们有了遥控器,如果想换台,按一下遥控器的换台按键,就可以实现换台。在这里,我们是通过遥控器发出的命令,所以遥控器相当于Invoker,命令发出者,我们相当于客户端,我们的责任是组装遥控器。遥控器上的每个具体按键,都是一个具体的命令。通过遥控器,就实现了我们和电视机之间的解耦。

  • Receiver角色
    Receiver是命令的具体执行者,我们在这里实现了四个命令逻辑,分别是,节目加,节目减,音量加,音量减。
/*
 * Receiver角色,真正的命令执行者
 * @author Jackson
 * @version 1.0.0
 * since 2019 05 09
 */
public class ChangeReceiver {

    /**
     * 真正处理节目加的逻辑
     */
     public void addItem(){
         System.out.println("节目+");
     }


    /**
     * 真正处理节目减的逻辑
     */
    public void subtractItem(){
         System.out.println("节目-");
     }


    /**
     * 真正处理音量加的逻辑
     */
    public void addVoice(){
        System.out.println("音量+");
    }

    /**
     * 真正处理音量减的逻辑
     */
    public void subtractVoice(){
        System.out.println("音量-");
    }
    
}
  • 命令接口
public interface Command {

   /**
    * 执行具体操作的命令
    */
   void execute();

}
  • 具体的命令
    分别是节目加,节目减,音量加,音量减四个具体命令。
public class AddItemCommand implements Command{

    // 持有一个接收者对象的引用
    private ChangeReceiver mChangeReceiver;

    public AddItemCommand(ChangeReceiver changeReceiver){
        this.mChangeReceiver=changeReceiver;
    }



    @Override
    public void execute() {
        // 调用遥控器的具体方法执行操作
        mChangeReceiver.addItem();
    }
}
public class SubtractItemCommand implements Command{

    // 持有一个接收者对象的引用
    private ChangeReceiver mChangeReceiver;

    public SubtractItemCommand(ChangeReceiver changeReceiver){
        this.mChangeReceiver=changeReceiver;
    }


    @Override
    public void execute() {
        // 调用遥控器的具体方法执行操作
        mChangeReceiver.subtractItem();
    }
}
public class AddVoiceCommand implements Command{

    // 持有一个接收者对象的引用
    private ChangeReceiver mChangeReceiver;

    public AddVoiceCommand(ChangeReceiver changeReceiver){
        this.mChangeReceiver=changeReceiver;
    }

    @Override
    public void execute() {
        // 调用遥控器的具体方法执行操作
        mChangeReceiver.addVoice();
    }
}
public class SubtractVoiceCommand implements Command{

    // 持有一个接收者对象的引用
    private ChangeReceiver mChangeReceiver;


    public SubtractVoiceCommand(ChangeReceiver changeReceiver){
        this.mChangeReceiver=changeReceiver;
    }

    @Override
    public void execute() {
        // 调用遥控器的具体方法执行操作
        mChangeReceiver.subtractVoice();
    }
}

  • 组装遥控器
    把四个命令按键安装到遥控器上,相当于Invoker,请求者角色。
public class RemoteControler {

    private AddItemCommand mAddItemCommand;       // 节目加命令对象的引用
    private SubtractItemCommand mSubtractItemCommand;  // 节目减命令的引用
    private AddVoiceCommand mAddVoiceCommand;         // 声音加命令的引用
    private SubtractVoiceCommand mSubtractVoiceCommand;  // 声音减命令的引用
    

    public void setAddItemCommand(AddItemCommand addItemCommand) {
        mAddItemCommand = addItemCommand;
    }
    

    public void setSubtractItemCommand(SubtractItemCommand subtractItemCommand) {
        mSubtractItemCommand = subtractItemCommand;
    }
    
    public void setAddVoiceCommand(AddVoiceCommand addVoiceCommand) {
        mAddVoiceCommand = addVoiceCommand;
    }


    public void setSubtractVoiceCommand(SubtractVoiceCommand subtractVoiceCommand) {
        mSubtractVoiceCommand = subtractVoiceCommand;
    }


    /**
     * 遥控器上的节目加按键
     */
    public void addItem(){
        mAddItemCommand.execute();
    }


    /**
     * 遥控器上的节目减按键
     */
    public void subtractItem(){
        mSubtractItemCommand.execute();
    }


    /**
     * 遥控器上的声音加按键
     */
    public void addVoice(){
        mAddVoiceCommand.execute();
    }

    /**
     * 遥控器上的声音减按键
     */
    public void subtractVoice(){
        mSubtractVoiceCommand.execute();
    }

    
}
  • 客户端代码
 // 首先要有一个接收者对象
        ChangeReceiver changeReceiver=new ChangeReceiver();
        // 构造四个命令
        AddItemCommand addItemCommand=new AddItemCommand(changeReceiver);
        SubtractItemCommand subtractItemCommand=new SubtractItemCommand(changeReceiver);
        AddVoiceCommand addVoiceCommand=new AddVoiceCommand(changeReceiver);
        SubtractVoiceCommand subtractVoiceCommand=new SubtractVoiceCommand(changeReceiver);

        // 组装遥控器,把代表不同命令的按键组装到遥控器上
        RemoteControler remoteControler=new RemoteControler();
        remoteControler.setAddItemCommand(addItemCommand);
        remoteControler.setSubtractItemCommand(subtractItemCommand);
        remoteControler.setAddVoiceCommand(addVoiceCommand);
        remoteControler.setSubtractVoiceCommand(subtractVoiceCommand);

        // 我们可以愉快地通过遥控器对电视发出遥控指令了
        remoteControler.addItem();
        remoteControler.subtractItem();
        remoteControler.addVoice();
        remoteControler.subtractVoice();

四 优缺点

优点

  • 类间解耦
    请求者与接收者之间没有任何依赖关系,请求者实现功能只需调用Command中的execute方法即可,不需要了解底层是哪个接收者。
  • 可扩展性
    Command具体的类可以非常容易扩展。

缺点
如果Command比较多,会造成类数目的膨胀。所以在实际开发中要不要采用命令模式还需要斟酌。


作者:Jackson杰
转自链接:https://www.jianshu.com/p/aa3e2fbe503b
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
原文地址:https://www.cnblogs.com/xifenglou/p/11394979.html