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

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

  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. 需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期。即最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的。可以通过该命令对象去调用请求接收者,而无须关系请求调用者的存在性,可以通过请求日志等机制来具体实现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

装饰器模式(Decorator)

装饰器模式是一种结构型设计模式&#xff0c;用来动态地给一个对象增加一些额外的职责。就增加对象功能来说&#xff0c;装饰器模式比生成子类实现更为灵活。装饰器模式的别名为包装器(Wrapper)&#xff0c;与适配器模式的别名相同&#xff0c;但它们适用于不同的场合。 Decor…

HTML笔记(1)

介绍 浏览器中内置了HTML的解析引擎&#xff0c;通过解析标记语言来展现网页&#xff1b;HTML标签都是预定义好的&#xff1b;Java工程师&#xff1a;后台代码的编写&#xff0c;和数据库打交道&#xff0c;把数据给网页前端的工程师&#xff1b;网页前端工程师&#xff1a;写H…

快速了解MyBatis---映射关系多对一

文章目录 映射关系多对一映射关系-官方文档映射关系多对1-基本介绍基本介绍注意细节 映射关系多对1-映射方式映射方式配置Mapper.xml 方式-应用实例注解实现多对1 映射-应用实例 映射关系多对一 映射关系-官方文档 文档地址: https://mybatis.org/mybatis-3/zh/sqlmap-xml.ht…

linux驱动定时器实现按键按下打印字符

#include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/interrupt.h>struct device_node *dev; unsigned int irqno; //中断处理函数 irqreturn_t myirq_handler(int irq,void *…

51单片机--红外遥控

文章目录 红外遥控的介绍硬件电路NEC编码外部中断红外遥控实例代码 红外遥控的介绍 红外遥控是一种无线、非接触控制技术&#xff0c;通过使用红外线来传送控制信号。它具有抗干扰能力强、信息传输可靠、功耗低、成本低、易实现等显著优点&#xff0c;因此被广泛应用于各种电子…

IDEA Debug小技巧 添加减少所查看变量、查看不同线程

问题 IDEA的Debug肯定都用过。它下面显示的变量&#xff0c;有什么门道&#xff1f;可以增加变量、查看线程吗&#xff1f; 答案是&#xff1a;可以。 演示代码 代码如下&#xff1a; package cn.itcast.attempt.threadAttempt.attempt2;public class Test {public static …

27岁到来之际,我在阿里实现了年薪30W+的小目标

毕业快 5 年了&#xff0c;每当和人聊起自己的职场飞升之路&#xff0c;都不由得感激当初果断逃离舒适圈的自己。出身一所非 211、985 院校&#xff0c;毕业后入职了一家小型互联网公司&#xff0c;当着普普通通的初级测试工程师&#xff0c;工作期间虽然也时常遇到挑战&#x…

HTTP之Session、Cookie 与 Application

目录 简介cookiecookie生命周期 sessionsession生命周期 HTTP cookies示例application 简介 cookie、seesion、application三个都会缓存我们用户状态的数据&#xff0c;使得我们在浏览器访问网站时可以更快速的获取到信息。 主要原因在于HTTP协议是无状态的&#xff0c;我们每…

计算机视觉(四)神经网络与典型的机器学习步骤

文章目录 神经网络生物神经元人工神经元激活函数导数 人工神经网络“层”的通俗理解 前馈神经网络Delta学习规则前馈神经网络的目标函数梯度下降输出层权重改变量 误差方向传播算法误差传播迭代公式简单的BP算例随机梯度下降&#xff08;SGD&#xff09;Mini-batch Gradient De…

搭建工程化项目

搭建工程化项目 首先创建一个 study 空文件夹&#xff0c;并且把它拖到 VS Code 里面。 在 VS Code 中打开终端&#xff0c;快捷键 ctrl ~ 在命令行中输入 npm init&#xff0c;在接下来所有选项中全部按 “回车” 采用默认即可。 初始化完毕后&#xff0c;在项目根目录下会出…

TypeScript 【type】关键字的进阶使用方式

导语&#xff1a; 在前面章节中&#xff0c;我们了解到 TS 中 type 这个关键字&#xff0c;常常被用作于&#xff0c;定义 类型别名&#xff0c;用来简化或复用复杂联合类型的时候使用。同时也了解到 为对象定义约束接口类型 的时候所使用的是 Interfaces。 其实对于前面&#…

C# Blazor 学习笔记(4):blazor代码分离

文章目录 前言代码分离 前言 Blazor可以支持在razor文件里面添加cs代码&#xff0c;但是代码一旦复杂了之后就会变得特别的麻烦。但是VS提供了代码分组的功能。 分离前 分离后 代码分离 我们直接右键razor组件是不能直接添加cs代码部分的 注意新建类的类名是xxx.razor…

软考中级信息安全工程师2023下半年报名时间及报名入口官网

软考中级信息安全工程师2023下半年考试时间&#xff1a; 2023年下半年软考中级信息安全工程师的考试时间为11月4日、5日。考试时间在全国各地一致&#xff0c;建议考生提前备考。共分两科&#xff0c;第一科基础知识考试具体时间为9:00-11:30&#xff1b;第二科应用技术考试具…

transformers里的AutoTokenizer之返回值token_type_ids(二)

在很多案例中&#xff0c;AutoTokenizer会返回token_type_ids这个结果&#xff1a; token_type_ids的解释&#xff1a; 对于两个句子对来说&#xff0c;上一句都标识为0&#xff0c;下一句都标识为1。

Hadoop优化

1.Datanode管理多块数据盘 1.理解 其实就是扩展Datanode空间,之前一个盘,现在加一个盘或者多个盘, 2.优点: 1.提高容错(避免硬盘损坏全部数据丢失)2.实现数据分离模式存储(框架本体与数据分离,集群出现问题数据可进行单独恢复,这样也是提高容错) 3.配置&#xff08;临时挂…

[PyTorch][chapter 45][RNN_2]

目录&#xff1a; RNN 问题 RNN 时序链问题 RNN 词组预测的例子 RNN简洁实现 一 RNN 问题 RNN 主要有两个问题&#xff0c;梯度弥散和梯度爆炸 1.1 损失函数 梯度 其中&#xff1a; 则 1.1 梯度爆炸&#xff08;Gradient Exploding&#xff09; 上面矩阵进行连乘后…

uniapp使用getStorage对属性赋值无效

1正常set(get)storage都是可以正常使用的 2.但对属性进行赋值的时候&#xff0c;却发现this.name并没有发生变化 3. 在里面打印this发现&#xff0c;在set*getStorage中并不能拿到this. 4.优化代码 这样就可以给this.name成功赋值

重学C++系列之STL库

一、什么是STL库 STL是“Standard Template Library”的缩写&#xff0c;中文翻译为“标准模板库”。CSTL是一套功能强大的C模板类&#xff0c;提供了通用的模板类和函数&#xff0c;这些模板类和函数可以实现多种流行和常用的算法和数据结构&#xff0c;如字符串操作、链表、队…

如何为新一代可持续应用设计电机编码器

从定速电机转向提供位置和电流反馈的变速电机&#xff0c;不仅可以实现工艺改进&#xff0c;还能节省大量能源。本文介绍了电机编码器&#xff08;位置和速度&#xff09;、器件类型和技术以及应用案例。此外还解答了一些关键问题&#xff0c;例如对特定系统最重要的编码器性能…