Java设计模式(16):命令模式

16,命令模式(Command)

16.1,问题引入_智能生活项目需求

  • 假如有一套智能家电,照明灯、风扇、空调、冰箱、洗衣机等,需要在手机上安装APP进行控制
  • 这些智能家电来自不同的厂家,每一个厂家针对设备都有不同的APP,但是我们不想下载那么多的APP,希望通过一个APP进行全控制,如万能遥控
  • 要实现一个APP控制所有智能家电的需要,则各个智能家电需要一个统一的接口提供给APP使用,这时候可以考虑命令模式
  • 命令模式可以将 动作的请求者动作的执行者 对象中解耦出来
  • 在这个例子中:动作的请求者是手机APP,动作的执行者就是各个智能家电

16.2,基本介绍

  • 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道请求的操作是哪个,我们只需要在程序运行时指定具体的请求接收者即可。此时,可以使用命令模式设计
  • 命令模式使得请求发送者和请求接收者消除彼此之间的耦合,让对象间的调用关系更加灵活,实现解耦
  • 命令模式中,会将一个请求封装为一个对象,使用不同的参数来表示不同的请求,同时命令模式也支持撤销操作
  • 用一个简单的解释:将军发送命令,士兵去执行。其中将军就是请求发送者,士兵是请求接收者,命令连接了将军和士兵
  • 命令模式在 Spring 框架中的 JDBCTemplate 模块中有被使用,StatementCallBack 接口是命令顶层接口

16.3,类图

在这里插入图片描述

  • Light:请求接收者,真正执行命令的角色,控制运行
  • Command:命令,也就是请求发送者和请求接收者的关联角色,知道如果实施和执行一个指令操作
  • LightXXCommand:具体命令角色,实现自 Command,将一个命令与一个功能绑定,通过命令实现功能
  • RemoteController:请求发送者,即APP万能遥控,通过按钮实现功能控制。每一个命令角色封装,对万能遥控的呈现即为一个按钮
  • Client:客户端,即操作人,通过APP进行控制

16.4,代码实现

  • Light:请求接收者,具体执行类

    package com.self.designmode.command;
    
    /**
     * 请求接收者: 具体工作类
     * @author PJ_ZHANG
     * @create 2020-12-10 13:52
     **/
    public class Light {
    
        public void on() {
            System.out.println("电灯打开了...");
        }
    
        public void off() {
            System.out.println("电灯关上了...");
        }
    
    }
    
  • Command:顶层命令接口,连接请求发起者和请求接收者

    package com.self.designmode.command;
    
    /**
     * 命令顶层接口
     * @author PJ_ZHANG
     * @create 2020-12-10 13:50
     **/
    public interface Command {
    
        /**
         * 执行操作
         */
        void execute();
    
        /**
         * 撤销操作
         */
        void undo();
    
    }
    
  • LightOnCommand:具体命令类,实际调度请求接收者的功能

    package com.self.designmode.command;
    
    /**
     * 具体命令, 对应某种功能
     * 打开电灯
     * @author PJ_ZHANG
     * @create 2020-12-10 13:54
     **/
    public class LightOnCommand implements Command {
    
        private Light light;
    
        public LightOnCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.on();
        }
    
        @Override
        public void undo() {
            light.off();
        }
    }
    
  • LightOffCommand:具体命令类,实际调度请求接收者的功能

    package com.self.designmode.command;
    
    /**
     * 具体命令, 对应某种功能
     * 关闭电灯
     * @author PJ_ZHANG
     * @create 2020-12-10 13:54
     **/
    public class LightOffCommand implements Command {
    
        private Light light;
    
        public LightOffCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.off();
        }
    
        @Override
        public void undo() {
            light.on();
        }
    }
    
  • NoCommand:命令空实现,作为预留部分

    package com.self.designmode.command;
    
    /**
     * @author PJ_ZHANG
     * @create 2020-12-10 14:02
     **/
    public class NoCommand implements Command {
    
        @Override
        public void execute() {
            System.out.println("do nothing,,,");
        }
    
        @Override
        public void undo() {
            System.out.println("do nothing,,,");
        }
    
    }
    
  • RemoteController:请求发起者,即万能遥控

    package com.self.designmode.command;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 请求发起者, 即万能遥控,
     * @author PJ_ZHANG
     * @create 2020-12-10 13:55
     **/
    public class RemoteController {
    
        private Map<String, Command> onCommandMap = new HashMap<>(16);
    
        private Map<String, Command> offCommandMap = new HashMap<>(16);
    
        private Command undoCommand;
    
        /**
         * 初始化开关
         * @param type
         * @param onCommand
         * @param offCommand
         */
        public void setCommand(String type, Command onCommand, Command offCommand) {
            onCommandMap.put(type, onCommand);
            offCommandMap.put(type, offCommand);
        }
    
        /**
         * 打开开关命令
         * @param type
         */
        public void onCommand(String type) {
            Command onCommand = null == onCommandMap.get(type) ? new NoCommand() : onCommandMap.get(type);
            onCommand.execute();
            undoCommand = onCommand;
        }
    
        /**
         * 关闭开关命令
         * @param type
         */
        public void offCommand(String type) {
            Command offCommand = null == offCommandMap.get(type) ? new NoCommand() : offCommandMap.get(type);
            offCommand.execute();
            undoCommand = offCommand;
        }
    
        /**
         * 撤销开关命令
         */
        public void undoCommand() {
            undoCommand.undo();
        }
    
    }
    
  • Client:客户端,用户操作

    package com.self.designmode.command;
    
    /**
     * 客户端操作
     * @author PJ_ZHANG
     * @create 2020-12-10 14:09
     **/
    public class Client {
    
        public static void main(String[] args) {
            // 初始化请求接收者,即实际执行类
            Light light = new Light();
            // 初始化具体命令类,即命令
            Command lightOnCommand = new LightOnCommand(light);
            Command lightOffCommand = new LightOffCommand(light);
            // 初始化遥控器, 即请求发起者
            RemoteController remoteController = new RemoteController();
            // 绑定命令
            remoteController.setCommand("1", lightOnCommand, lightOffCommand);
            // 开灯
            remoteController.onCommand("1");
            // 关灯
            remoteController.offCommand("1");
            // 撤销
            remoteController.undoCommand();
            // 如果需要添加其他智能家居,
            // 只需要添加请求接收者和对应的具体命令类
            // 在初始化遥控器时设置为不同的type即可
        }
    
    }
    

16.5,命令模式的注意事项和细节

  • 将发起请求的对象和执行请求的对象解耦。发起请求的对象是调用者,调用者只需要调用命令对象的 execute() 方法可以让接口者工作,而不必知道接收者是谁、是如何工作的。命令对象会负责让对应的接收者执行工作。也就是说 请求发起者请求接受者 是完全解耦的,命令对象在中间起连接作用
  • 比较容易的设计一个命令队列。只需要将命令放入队列中,就可以进行多线程控制
  • 比较容易的实现对请求的撤销和重做
  • 空命令也是命令模式的一种设计,省去了判空操作,对命令进行了基础的空实现
  • 命令模式的应用场景:界面的一个按钮都是一个命令,模拟基于命令的订单撤销、恢复、触发、反馈机制
  • 命令模式不足:可能导致某些系统有过多的具体命令类,增加系统复杂性
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值