美文网首页
设计模式《命令模式》

设计模式《命令模式》

作者: 天道__ | 来源:发表于2018-08-13 18:15 被阅读0次

引言

  设计模式部分马上就要结尾,终于系统性的写完了一块。先放出上一节的备忘录模式。这节我们说说命令模式。

示例地址

  Demo

类图

image

定义

  将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式的使用场景

  1. 需要抽象出待执行的动作,然后以参数的形式提供出来类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品。
  2. 在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始请求无关的生存期。
  3. 需要支持取消操作。
  4. 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍。
  5. 需要支持事务操作。

命令模式中的角色

  Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。

  ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。

  Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。

  Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。

经典示例

1. 接收者
/**
 * 接收者
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:20.
 */
public class Receiver {
    public void action() {
        System.out.println("我来执行任务");
    }
}
2. 命令接口
/**
 * 命令接口
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:14.
 */
public interface ICommand {
    public void execute();
}
3. 命令接口的实现
/**
 * 命令接口的实现
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:14.
 */
public class ConcreteCommand implements ICommand {
    private Receiver mReceiver;

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

    @Override
    public void execute() {
        mReceiver.action();
    }
}
4. 调用者
/**
 * 调用者
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:21.
 */
public class Invoker {
    /**
     * 持有命令对象
     */
    private ICommand command = null;

    /**
     * 设置调用者持有的命令对象
     *
     * @param command 命令对象
     */
    public void setCommand(ICommand command) {
        this.command = command;
    }

    /**
     * 示意方法,要求命令执行请求
     */
    public void runCommand() {
        //调用命令对象的执行方法
        command.execute();
    }

}
5. Client
    //经典示例
    ConcreteCommand concreteCommand = new ConcreteCommand(new Receiver());

    Invoker invoker = new Invoker();
    invoker.setCommand(concreteCommand);
    invoker.runCommand();

实际运用

  生活中存在很多这样的案例,例如我们通过开关可以控制一些电器的打开和关闭,例如电灯或者油烟机。开关与电器之间通过电线建立连接,如果开关打开,则电线通电,电器工作;反之,开关关闭,电线断电,电器停止工作。
  在命令模式中,发送者与接收者之间引入了新的命令对象(电线),将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法,从而实现解耦。

1. 开灯 关灯实际接收者
/**
 * 开灯 关灯实际接收者
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午4:58.
 */
public class LightReceiver  {
    public void on() {
        System.out.println("开灯");
    }

    public void off() {
        System.out.println("关灯");
    }
}
2. 油烟机的接收者
/**
 * 油烟机的接收者
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午5:12.
 */
public class ExhaustReceiver {
    public void on() {
        System.out.println("开油烟机");
    }

    public void off() {
        System.out.println("关油烟机");
    }
}
3. 命令接口
/**
 * 命令接口
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:14.
 */
public interface ICommand {
    public void execute();
}
4. 开灯 关灯命令
/**
 * 开灯 关灯命令
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午4:48.
 */
public class LightCommand implements ICommand {

    private LightReceiver mLightReceiver;

    public LightCommand(LightReceiver lightReceiver) {
        mLightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        mLightReceiver.on();
        mLightReceiver.off();
    }
}
5. 开 关 吸油烟机命令
/**
 * 开 关 吸油烟机命令
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午4:51.
 */
public class ExhaustCommand implements ICommand {
    private ExhaustReceiver mExhaustReceiver;

    public ExhaustCommand(ExhaustReceiver exhaustReceiver) {
        mExhaustReceiver = exhaustReceiver;
    }

    @Override
    public void execute() {
        mExhaustReceiver.on();
        mExhaustReceiver.off();
    }
}
6. 调用者
/**
 * 调用者
 *
 * @author 512573717@qq.com
 * @created 2018/8/13  下午3:21.
 */
public class Invoker {
    /**
     * 持有命令对象
     */
    private ICommand command = null;

    /**
     * 设置调用者持有的命令对象
     *
     * @param command 命令对象
     */
    public void setCommand(ICommand command) {
        this.command = command;
    }

    /**
     * 示意方法,要求命令执行请求
     */
    public void runCommand() {
        //调用命令对象的执行方法
        command.execute();
    }
}
7. Client
    //开关案例
    Invoker invoker=new Invoker();

    LightCommand lightCommand = new LightCommand(new LightReceiver());
    ExhaustCommand exhaustCommand = new ExhaustCommand(new ExhaustReceiver());

    // 请求
    System.out.println("开灯 关灯命令=============");
    invoker.setCommand(lightCommand);
    invoker.runCommand();

    System.out.println("开油烟机  关油烟机命令=============");
    invoker.setCommand(exhaustCommand);
    invoker.runCommand();

总结

  优点
  • 降低系统的耦合度
  • 新的命令可以很容易地加入到系统中
  • 可以比较容易地设计一个命令队列或宏命令
  缺点
  • 使用命令模式可能会导致某些系统有过多的具体命令类

相关文章

网友评论

      本文标题:设计模式《命令模式》

      本文链接:https://www.haomeiwen.com/subject/qfoubftx.html