命令模式-请求发送者与接收者解耦

news2024/9/20 12:28:32

 去小餐馆吃饭的时候,顾客直接跟厨师说想要吃什么菜,然后厨师再开始炒菜。去大点的餐馆吃饭时,我们是跟服务员说想吃什么菜,然后服务员把这信息传到厨房,厨师根据这些订单信息炒菜。为什么大餐馆不省去这个步骤,像小餐管那样点菜呢?原因主要有以下几点:

  1. 提供效率。厨师专注炒菜就行,而不必花时间跟客户接触。
  2. 各司其职,提高服务质量。厨师擅长炒菜,而服务员擅长跟顾客打交道。
  3. 使工作有条不紊的进行。不会像小餐馆那样,来了个新客户,需要马上停止炒菜,去招呼客人,而另一边客户要在催着上菜。
  4. 阻断客户与厨师的接触。客户无须知道炒菜的厨师是谁,厨师也不需要知道他为谁炒的菜。

在这里,服务员发挥着“命令”的作用,将客户的命令传递给厨师,厨师做出相应。而这种模式是一种“命令模式”。

1 命令模式概述

引入一个命令类,通过命令类来降低发送者和接收者的耦合度。将一个请求封装成一个命令对象,发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。

图 命令模式结构图

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

ConcreteCommand:具体命令类,对应具体接收者对象,维护了一个接收者对象的引用,在实现execute()方法时,将调用接收者对象的相关操作(action()方法等)。

Invoker:调用者,即请求发送者。通过命令对象来执行请求。

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

public interface Command {

    String getName();

    void makeOrder(String name);

}

public class WaiterCommand implements Command{

    private final String name;

    private CookReceiver cookReceiver;

    public WaiterCommand(String name, CookReceiver cookReceiver) {
        this.name = name;
        this.cookReceiver = cookReceiver;
    }

    public void setCookReceiver(CookReceiver cookReceiver) {
        this.cookReceiver = cookReceiver;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void makeOrder(String name) {
        System.out.print("  " + cookReceiver.getName() + ":");
        cookReceiver.cooking(name);
    }

}
public class CookReceiver {

    private final String name;

    public CookReceiver(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void cooking(String name) {
        System.out.println("开始做菜:" + name);
    }

}
public class CustomerInvoker {

    private Command waiter;

    public CustomerInvoker(Command waiter) {
        this.waiter = waiter;
    }

    public void changeWaiter(Command waiter) {
        this.waiter = waiter;
    }

    public void makeOrder(String name) {
        System.out.print(waiter.getName() + "为客户下单");
        waiter.makeOrder(name);
    }

}
public class Client {

    private final static List<Command> waiterList = new ArrayList<>();

    static {
        CookReceiver cook1 = new CookReceiver("黄师傅");
        CookReceiver cook2 = new CookReceiver("刘师傅");

        waiterList.add(new WaiterCommand("小李",cook1));
        waiterList.add(new WaiterCommand("小张",cook2));
        waiterList.add(new WaiterCommand("小王", cook1));
    }

    public static void main(String[] args) {
        String[] menu = {"辣椒炒肉","剁椒鱼头","清蒸豆腐","爆炒花甲","酸辣螺蛳粉"};
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            CustomerInvoker invoker = new CustomerInvoker(waiterList.get(random.nextInt( waiterList.size())));
            invoker.makeOrder(menu[random.nextInt(menu.length)]);
            System.out.println("--------------");
        }
//        运行结果:
//        小王为客户下单  黄师傅:开始做菜:酸辣螺蛳粉
//        --------------
//        小王为客户下单  黄师傅:开始做菜:辣椒炒肉
//         --------------
//        小张为客户下单  刘师傅:开始做菜:剁椒鱼头
//        --------------
//        小张为客户下单  刘师傅:开始做菜:爆炒花甲
//        --------------
//        小王为客户下单  黄师傅:开始做菜:辣椒炒肉
//        --------------
//        小王为客户下单  黄师傅:开始做菜:酸辣螺蛳粉
//        --------------
    }

}

命令模式的本质是对请求进行封装,一个请求对应一个命令。将发送命令与执行命令分割开,但不能减少类的数量。

1.1 命令队列

一个请求发送者发送一个请求时,不止一个请求接收者产生响应,这些接收者将逐个执行业务方法,完成对请求的处理。

图 命令队列结构图

2 优缺点

优点:

  1. 降低系统的耦合度,请求者与接收者之间完全解耦,相同的请求者可对应不同的接收者。同样,相同的接收者也也可以供不同的请求者使用,两者具有良好的独立性。
  2. 新的命令可用很容易地加入系统中。增加新的具体命令不会影响其他类,符合开闭原则。
  3. 笔记容易设计一个命令队列或宏命令。
  4. 为请求的撤销和恢复操作提供了一种设计和实现方案。

缺点:

1)会导致系统有过多的具体命令类。

3 适用场景

  1. 需要将请求调用者和请求接收者解耦。
  2. 系统需要支持命令的撤销和恢复操作。
  3. 需要将一组操作组合在一起形成宏命令。
  4. 需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期。即最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的。可以通过该命令对象去调用请求接收者,而无须关系请求调用者的存在性,可以通过请求日志等机制来具体实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/821780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JVM】(一)深入理解JVM运行时数据区

文章目录 一、JVM 运行流程二、虚拟机栈&#xff08;线程私有&#xff09;三、本地方法栈 &#xff08;线程私有&#xff09;四、方法区&#xff08;元数据区&#xff09;五、堆&#xff08;线程共享&#xff09;六、程序计数器&#xff08;线程私有&#xff09; 一、JVM 运行流…

安装Apache遇到的问题

安装Apache服务 httpd -k install -n Apache2.4 #-n后面表示自定义访问名称 问题1&#xff1a; 此时去 windows 的开始摁扭里找到控制器右键管理员运行 问题2&#xff1a; 命令行没用对 应该用&#xff1a; .\httpd -k install -n Apache2.4 #-n后面表示自定义访问名称

远程控制平台四之优化部署

服务器端打包 把服务器打成jar包对于后台开发的朋友来说小菜一碟,但对于前端开发可能有些细节要注意一下,尤其是有依赖其他第三方库的情况下,这里梳理了一下流程: File – Project Structure – Artifacts – add – JAR – From modules and dependencies 选中module和主…

前端构建(打包)工具发展史

大多同学的前端学习路线&#xff1a;三件套框架慢慢延伸到其他&#xff0c;在这个过程中&#xff0c;有一个词出现的频率很高&#xff1a;webpack 。 作为一个很出名的前端构建工具我们在网上随便一搜&#xff0c;就会有各种教程&#xff1a;loader plugin entry吧啦吧啦。 但…

嵌入式Linux的学习嵌入式一开始该怎么学?

把握以下几点&#xff1a; 文件 进程&#xff0c;线程&#xff0c;信号 进程&#xff0c;线程通信同步 网络&#xff1a;这个简单&#xff0c;就那几个API&#xff0c;TCP和udp。 嵌入式Linux 目前我正在学&#xff0c;我看到资料是正点原子&#xff0c;野火和韦东山作为参…

在中国人民大学与加拿大女王大学金融硕士项目中蜕变,成长

毕业十年后&#xff0c;还想得起大学时你的样子吗&#xff1f;有人这十年浑浑噩噩&#xff0c;或过着按部就班的日子&#xff0c;渐渐认命了&#xff1b;也有人用这十年实现了底层逆袭&#xff0c;完成了华丽的人生转身。如中国人民大学与加拿大女王大学金融硕士项目&#xff0…

栈的压入,弹出序列

栈的压入弹出序列问题可以通过模拟栈的压入和弹出过程来解决。 具体思路如下&#xff1a; 定义一个辅助栈&#xff0c;用于模拟压栈和弹栈操作。遍历给定的压栈序列&#xff0c;在每一次循环中执行以下操作&#xff1a; 将当前元素压入辅助栈。循环检查辅助栈的栈顶元素是否与…

SQL-每日一题【1158. 市场分析 I】

题目 Table: Users Table: Orders Table: Items 请写出一条SQL语句以查询每个用户的注册日期和在 2019 年作为买家的订单总数。 以 任意顺序 返回结果表。 查询结果格式如下。 示例 1: 解题思路 1.题目要求我们查询每个用户的注册日期和在 2019 年作为买家的订单总数。我们可…

天工开物 #7 Rust 与 Java 程序的异步接口互操作

许多语言的高性能程序库都是建立在 C/C 的核心实现上的。 例如&#xff0c;著名 Python 科学计算库 Pandas 和 Numpy 的核心是 C 实现的&#xff0c;RocksDB 的 Java 接口是对底层 C 接口的封装。 Rust 语言的基本目标之一就是替代 C 在这些领域的位置&#xff0c;为开发者提供…

Python+PyQt5来模拟实现多人聊天

一、界面功能展示 1、设置一个通信 用户1 2、设置通信 用户2 3、进入聊天功能界面 4、发送信息来实现实时通信 二、代码实现 &#xff08;要源码请留言&#xff09;

Spring框架中的@Configuration参数proxyBeanMethods

一.概念分析 在Spring框架中&#xff0c;Configuration注解用于声明一个Java类作为配置类&#xff0c;它替代了传统的XML配置方式。通过Configuration注解标记的类可以包含Bean注解&#xff0c;用于定义Spring容器中的Bean对象。而在Configuration注解中&#xff0c;有一个非常…

HarmonyOS 开发基础(三)登录页面单向数据绑定(父组件向子组件传参)

一、目录结构认识 开发软件目录截图部分文件夹说明 文件组织结构图 二、完成单向数据绑定 index.etx // 导出方式直接从文件夹 import MyInput from "../common/commons/myInput" Entry Component /* 组件可以基于struct实现&#xff0c;组件不能有继承关系&am…

【JavaWeb】Javascript经典案例

Javascript经典案例 注意&#xff1a;该文章是参考b站<20个JS经典案例>进行学习的&#xff0c;没有CSS的组成。 在慢慢更新中…哈哈哈哈&#xff0c;太慢了 文章目录 1.支付定时器2.验证码生成及校验 1.支付定时器 代码实现&#xff1a; confirm.html <!DOCTYPE html…

动嘴操控“终结者”谷歌打造最强chatgpt机器人

我们知道&#xff0c;在掌握了网络中的语言和图像之后&#xff0c;大模型终究要走进现实世界&#xff0c;「具身智能」应该是下一步发展的方向。把大模型接入机器人&#xff0c;用简单的自然语言代替复杂指令形成具体行动规划&#xff0c;且无需额外数据和训练&#xff0c;这个…

Ubuntu-文件和目录相关命令

&#x1f52e;linux的文件系统结构 ⛳目录结构及目录路径 &#x1f9e9;文件系统层次结构标准FHS Filesystem Hierarchy Standard(文件系统层次结构标准&#xff09; Linux是开源的软件&#xff0c;各Linux发行机构都可以按照自己的需求对文件系统进行裁剪&#xff0c;所以众多…

【Redis】内存数据库Redis进阶(Redis主从集群)

目录 分布式缓存 Redis 四大问题搭建Redis主从集群主从数据同步原理全量同步master 如何得知 salve 是第一次来连接&#xff08;Replication Id与offset&#xff09; 增量同步master怎么知道slave与自己的数据差异在哪里&#xff08;repl_backlog原理&#xff09; 主从同步优化…

根据中序遍历和后序遍历构建二叉树(递归和迭代两种方法实现)

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&#xff1a;[3,9,20,nu…

python使用selenium 打开谷歌浏览器闪退, 怎么解决

问题描述&#xff1a; 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 使用 Selenium 操作 Chrome 浏览器&#xff0c; Chrome 浏览器闪退 问题解决&#xff1a; 可能是以下几个方面出现了问题&#xff1a; 1. Chromedriver 版本与 Chrome 浏览器版本不匹配 你需要确保你正在…

cmake升级(ubuntu 18.04)——千万不要删除原来版本的cmake

重要提示 千万不要卸载删除ubuntu原有的cmake&#xff0c;否则之前经过原有cmake编译过的文件将也会被删除&#xff0c;比如 ros。 千万不要使用下面这句命令删除原有的 cmake &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 超级大坑&#xff0c;…

Linux第八章之进程概念

一、冯诺依曼体系结构 关于冯诺依曼&#xff0c;必须强调几点&#xff1a; 这里的存储器指的是内存不考虑缓存情况&#xff0c;这里的CPU能且只能对内存进行读写&#xff0c;不能访问外设(输入或输出设备)外设(输入或输出设备)要输入或者输出数据&#xff0c;也只能写入内存或…