• 【深入理解设计模式】命令设计模式


    在这里插入图片描述

    命令设计模式

    命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,从而使你可以用不同的请求对客户端进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

    概述

    日常生活中,我们出去吃饭都会遇到下面的场景。

    在这里插入图片描述
    定义:

    将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。

    结构

    命令模式包含以下主要角色:

    • 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。
    • 具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
    • 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
    • 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

    命令模式的结构如下:

    1. 定义一个命令接口,声明一个执行命令的方法。
    2. 创建具体命令类,实现命令接口,并实现具体的命令。
    3. 创建一个调用者类,用于调用命令对象的方法。
    4. 在客户端代码中,创建命令对象,并调用其方法。

    下面是一个简单的命令模式示例:

    // 命令接口
    public interface Command {
        void execute();
    }
    
    // 具体命令类1
    public class ConcreteCommand1 implements Command {
    	// 接收者
        private Receiver receiver;
    
        public ConcreteCommand1(Receiver receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            receiver.action1();
        }
    }
    
    // 具体命令类2
    public class ConcreteCommand2 implements Command {
    	// 接收者
        private Receiver receiver;
    
        public ConcreteCommand2(Receiver receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            receiver.action2();
        }
    }
    
    // 接收者类
    public class Receiver {
        public void action1() {
            System.out.println("执行操作1");
        }
    
        public void action2() {
            System.out.println("执行操作2");
        }
    }
    
    // 调用者类
    public class Invoker {
        private Command command;
    
        public void setCommand(Command command) {
            this.command = command;
        }
    
        public void executeCommand() {
            command.execute();
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            Receiver receiver = new Receiver();
            Command command1 = new ConcreteCommand1(receiver);
            Command command2 = new ConcreteCommand2(receiver);
    
            Invoker invoker = new Invoker();
            invoker.setCommand(command1);
            invoker.executeCommand(); // 输出:执行操作1
    
            invoker.setCommand(command2);
            invoker.executeCommand(); // 输出:执行操作2
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    在这个示例中,我们定义了一个命令接口,两个具体命令类,以及一个接收者类和一个调用者类。客户端创建命令对象,并调用其方法。

    案例实现

    将上面的案例用代码实现,那我们就需要分析命令模式的角色在该案例中由谁来充当。

    服务员: 就是调用者角色,由她来发起命令。

    资深大厨: 就是接收者角色,真正命令执行的对象。

    订单: 命令中包含订单。

    类图如下:
    在这里插入图片描述
    代码如下:

    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 抽象命令
     */
    public interface Commend {
    
        void execute();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 订单类
     */
    public class Order {
    
        // 餐桌号
        private int diningTable;
    
        // 用来存储餐名并记录份数
        private final Map<String, Integer> foodDic = new HashMap<String, Integer>();
    
    
        public int getDiningTable() {
            return diningTable;
        }
    
        public void setDiningTable(int diningTable) {
            this.diningTable = diningTable;
        }
    
        public Map<String, Integer> getFoodDic() {
            return foodDic;
        }
    
        public void setFood(String food, int num) {
            foodDic.put(food, num);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 订单命令
     */
    public class OrderCommend implements Commend {
    
        // 持有接受者对象 -> 执行命令的对象
        private final SeniorChef seniorChef;
        // 订单
        private final Order order;
    
        public OrderCommend(SeniorChef seniorChef, Order order) {
            this.seniorChef = seniorChef;
            this.order = order;
        }
    
        @Override
        public void execute() {
            System.out.println(order.getDiningTable() + "桌的订单");
            Map<String, Integer> foodDic = order.getFoodDic();
            Set<String> foodNames = foodDic.keySet();
            for (String foodName : foodNames) {
                seniorChef.createFood(foodDic.get(foodName), foodName);
            }
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
    
    
            System.out.println(order.getDiningTable() + "桌的饭弄好了");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 厨师类 - 命令接收者
     */
    public class SeniorChef {
    
        public void createFood(int num, String food) {
            System.out.println(num + "份" + food );
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 服务员对象 - 命令的请求者
     */
    public class Waiter {
    	// 可同时持有多个命令
        private final List<Commend> commends = new ArrayList<>();
    
        public void setCommends(Commend commend) {
            commends.add(commend);
        }
    
        public void orderUp() {
            System.out.println("订单来了!");
            for (Commend commend : commends) {
                commend.execute();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    /**
     * @author OldGj 2024/03/09
     * @version v1.0
     * @apiNote 测试类 - 客户端
     */
    public class Client {
        public static void main(String[] args) {
            // 创建订单
            Order order1 = new Order();
            order1.setDiningTable(1);
            order1.setFood("爆炒河粉",2);
            order1.setFood("可乐",2);
            Order order2 = new Order();
            order2.setDiningTable(2);
            order2.setFood("肉丝",2);
            order2.setFood("雪碧",2);
    
            //创建厨师
            SeniorChef seniorChef = new SeniorChef();
    
            // 创建命令
            Commend commend = new OrderCommend(seniorChef,order1);
            Commend commend2 = new OrderCommend(seniorChef,order2);
    
            // 创建服务员
            Waiter waiter = new Waiter();
            waiter.setCommends(commend);
            waiter.setCommends(commend2);
            waiter.orderUp();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    命令模式的主要优点是:

    1. 命令对象将动作的请求与执行请求的对象解耦,使得可以很方便地扩展或修改行为。
    2. 命令对象可以记录请求的日志,可以进行撤销和重做操作。
    3. 命令对象可以实现宏命令,一组命令可以组合成一个命令对象。

    命令模式的主要缺点是:

    1. 命令对象可能过多,导致程序性能下降。
    2. 命令对象可能需要实现一些公共接口,导致代码冗余。系统结构更加复杂。

    使用场景

    • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
    • 系统需要在不同的时间指定请求、将请求排队和执行请求。
    • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • 相关阅读:
    四氧化三铁Fe3O4/二氧化硅SiO2/二氧化钛TIO2/氧化锌ZNO/二氧化锰MnO2/二硫化钨MoS2/二硒化钨WSe2/碲化钨WTe2纳米粒包载顺铂
    最强辅助!阿里最新总结22年大厂Java面试真题+核心知识点全面覆盖+答案详解!
    华为云云耀云服务器L实例评测|Docker版的Minio安装 & Springboot项目中的使用 & 结合vue进行图片的存取
    ComSec作业三:RSA
    带绝对值的数可导性问题的讨论
    一文概览NLP句法分析:从理论到PyTorch实战解读
    SpringWeb(SpringMVC)
    Java进阶篇--LockSupport
    Java-API简析_java.util.PropertyPermission类(基于 Latest JDK)(浅析源码)
    【云原生之Docker实战】使用Docker部署WBO在线协作白板
  • 原文地址:https://blog.csdn.net/guojiaqi_/article/details/136679992