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

设计模式《命令模式》

作者: 天道__ | 来源:发表于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