第十五章行为性模式—命令模式

news2024/11/16 12:39:48

文章目录

  • 命令模式
    • 解决的问题
    • 结构
    • 实例
    • 存在的问题
    • 适用场景
  • JDK 源码 - Runnable

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式:

  • 类行为模式:采用继承机制来在类间分派行为

  • 对象行为模式:采用组合或聚合在对象间分配行为

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

行为型模式分为:

  • 模板方法模式
  • 策略模式
  • 命令模式
  • 职责链模式
  • 状态模式
  • 观察者模式
  • 中介者模式
  • 迭代器模式
  • 访问者模式
  • 备忘录模式
  • 解释器模式

以上 11 种行为型模式,除了模板方法模式解释器模式是类行为型模式,其他的全部属于对象行为型模式。

命令模式

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

命令模式是一种行为设计模式**,它将请求转换为一个包含与请求相关的所有信息的独立对象**,该转换让你能够根据不同的请求将方法参数化,延迟请求执行或者将其放入队列中,且能够实现可撤销操作

解决的问题

image-20230517164359677

  • 客户点菜是通过服务员,所以发送请求的责任属于服务员
  • 具体的菜品是厨师进行烹饪,所以执行请求的测试的属于厨师
  • 将发送请求的责任与执行请求的责任分开

结构

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

实例

image-20230517165531278

分析命令模式的角色在该案例中由谁来充当:

  • 服务员: 就是调用者角色,由她来发起命令。
  • 资深大厨: 就是接收者角色,真正命令执行的对象。
  • 订单: 命令中包含订单。

抽象命令类

public interface Command {
    void execute();
}

具体命令类

public class OrderCommand implements  Command{
    private SeniorChef receiver;
    private Order order;
    public OrderCommand(SeniorChef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }
    @Override
    public void execute() {
        System.out.println(order.getDiningTable() + "桌的订单:");
        Map<String, Integer> foodDir = order.getFoodDir();
        Set<String> keys = foodDir.keySet();
        for (String foodName : keys) {
            receiver.makeFood(foodName, foodDir.get(foodName));
        }
        System.out.println(order.getDiningTable() + "桌的饭准备完毕!!!");

    }
}
/**
 * 订单类
 */
@Data
public class Order {
    // 餐桌号码
    private int diningTable;
    // 所下的餐品及份数
    private Map<String,Integer> foodDir = new HashMap<>();

    public void setFood(String name, int num) {
        foodDir.put(name,num);
    }
}

  • 聚合了接收者

接收者:资深大厨

public class SeniorChef {
    public void makeFood(String name,int num) {
        System.out.println(num + "份" + name);
    }
}

调用者:服务员

public class Waiter {
    //持有多个命令对象
    private List<Command> commands=new ArrayList<>();
    public void setCommand(Command cmd) {
        // 将命令类对象存储到list集合中
        commands.add(cmd);
    }
    // 发起命令功能: 喊 订单来了
    public void orderUp() {
        System.out.println("美女服务员:大厨,新订单来了。。。。");
        for (Command command : commands) {
            if(command != null) {
                command.execute();
            }
        }
    }
}
  • 调用者中聚合了命令对象
  • 我们这里调用者就将我们的命令对象放入了队列中,这种我们的可以命令对象进行操作,比如延迟执行,当然也可以做到了我们的撤销等操作

测试

public class Client {
    public static void main(String[] args) {
        // 创建第二个订单对象
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.setFood("西红柿鸡蛋面",1);
        order1.setFood("小杯可乐",2);
        // 创建第二个订单对象
        Order order2 = new Order();
        order2.setDiningTable(2);
        order2.setFood("尖椒肉丝盖饭",1);
        order2.setFood("小杯雪碧",1);
        //创建接收者对象 厨师
        SeniorChef receiver = new SeniorChef();
        //创建命令对象
        OrderCommand orderCommand1 = new OrderCommand(receiver, order1);
        OrderCommand orderCommand2 = new OrderCommand(receiver, order2);
        // 创建调用者(服务员对象)
        Waiter invoke = new Waiter();
        invoke.setCommand(orderCommand1);
        invoke.setCommand(orderCommand2);
        //让服务员发起命令
        invoke.orderUp();
    }
}
美女服务员:大厨,新订单来了。。。。
1桌的订单:
1份西红柿鸡蛋面
2份小杯可乐
1桌的饭准备完毕!!!
2桌的订单:
1份尖椒肉丝盖饭
1份小杯雪碧
2桌的饭准备完毕!!!

存在的问题

优点:

  • 降低系统的耦合度。命令模式能将调用操作的对象实现该操作的对象解耦。

  • 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足 “开闭原则”,对扩展比较灵活。

  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。

  • 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

缺点:

  • 使用命令模式可能会导致某些系统有过多的具体命令类。
  • 系统结构更加复杂。

适用场景

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求
  • 系统需要支持命令的撤销 (Undo) 操作和恢复 (Redo) 操作。

JDK 源码 - Runnable

Runable 是一个典型命令模式,Runnable 担当命令的角色,Thread 充当的是调用者,start 方法就是其执行方法

  • 调用者和接收者分离了
// 命令接口(抽象命令角色)
public interface Runnable {
	public abstract void run();
}

// 调用者
public class Thread implements Runnable {
    private Runnable target;
    
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    
    private native void start0();
}

start 方法会调用一个 native 方法 start0(),调用系统方法,开启一个线程。而接收者是对程序员开放的,可以自己定义接收者。

/**
 * jdk Runnable 命令模式
 * TurnOffThread:属于具体命令
 */
public class TurnOffThread implements Runnable{
     private Receiver receiver;
    
     public TurnOffThread(Receiver receiver) {
     	this.receiver = receiver;
     }
     public void run() {
     	receiver.turnOFF();
     }
}

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

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

相关文章

OW-DETR: Open-world Detection Transformer(论文翻译)

文章目录 OW-DETR: Open-world Detection Transformer摘要1.介绍2.开放世界检测的transformer2.1整体架构2.2.多尺度上下文编码2.3.注意力驱动的伪标签2.4 新类分类2.5.前景物体2.6.训练与推理 3.实验3.1.最新技术水平比较3.2.增量目标检测3.3 消融实验 4.与现有技术的关系5.结…

【干货收藏】 隔离驱动SLMi335/SLMi335H 电路方案分享

数明深力科SLMi33X系列SLMi335/SLMi335H首款单通道带DESAT保护功能的IGBT/SiC隔离驱动器。内置快速去饱和(DESAT) 故障检测功能、米勒钳位功能、漏极开路故障反馈、软关断功能以及可选择的自恢复模式&#xff0c;兼容光耦隔离驱动器。 SLMi33X系列SLMi335/SLMi335H的DESAT阈值…

如何搭建高质量的 B 端产品帮助体系?

在B2B市场中&#xff0c;产品的质量和支持服务对于企业的成功至关重要。帮助中心是B2B企业提供优质支持服务的重要组成部分。那么&#xff0c;如何搭建高质量的B端产品帮助体系呢&#xff1f;本文将为大家介绍一些关键的步骤和方法。 一、了解用户需求 首先&#xff0c;要搭建…

【ZYNQ】QSPI Flash 固化程序全攻略

普通的 FPGA 一般是可以从 Flash 启动&#xff0c;或者被动加载&#xff0c;ZYNQ 的启动是由 ARM 主导的&#xff0c;包括 FPGA 程序的加载&#xff0c;ZYNQ 启动一般为最少两个步骤&#xff0c;在 UG585 中也有介绍。 Stage 0&#xff1a;BootROM 阶段 在 ZYNQ 上电复位或者热…

前端异步请求并解决跨域问题(Ajax+axios框架)、后端响应多个数据(JSON)

目录 一、前后端同步异步请求 1.同步请求&#xff1a; 2.异步请求&#xff1a; 3.跨域问题&#xff08;前端问题&#xff09; 4.axios框架&#xff08;封装后&#xff09; 二、后端向前端响应多个数据-JSON 一、前后端同步异步请求 1.同步请求&#xff1a; 发送一个请求…

【Java多线程进阶】CAS机制

前言 CAS指的是Compare-And-Swap&#xff08;比较与交换&#xff09;&#xff0c;它是一种多线程同步的技术&#xff0c;常用于实现无锁算法&#xff0c;从而提高多线程程序的性能和扩展性。本篇文章具体讲解如何使用 CAS 的机制以及 CAS 机制带来的问题。 目录 1. 什么是CAS&…

《机器学习算法竞赛实战》-chapter4特征工程

《机器学习算法竞赛实战》学习笔记&#xff0c;记录一下自己的刷题过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 特征工程 特征工程是算法竞赛中工作量最大&#xff0c;决定参赛者能否拿到较好名次的关键部分。吴恩达老师说过&#xff1a;“机器学习在本质上还是特…

Maven Compile时报错 [ERROR] [X Group Enforcer Rules] find DuplicateClasses

类冲突 [ERROR] [Ctrip Group Enforcer Rules] find DuplicateClasses Found in: net.jpountz.lz4:lz4:jar:1.3.0:compile org.lz4:lz4-java:jar:1.7.1:compile Duplicate classes: net/jpountz/xxhash/AbstractStreamingXXHash32Java.class net/jpountz/lz4/LZ4BlockInputStre…

Arduino+ESP8266 MCU开发板 ----带你开发 (TCP)双向局域网通信 项目-----可开发成为小远程控制

目录 本次需要下载的代码链接&#xff1a; 文章项目引用&#xff1a;本次实现可依据之前的文章就行举一反三的操作 本次开发项目步1&#xff1a;下载Aeduino软件 本次开发项目步2&#xff1a; 更替代码片段1 第13行 代替账号和密码 更替代码片段2 第20行 …

软件科技项目验收有哪些注意事项?第三方软件验收测试的好处在哪?

软件科技项目的验收是软件生产周期中非常重要的一个环节。它主要目的是验证软件产品是否满足用户需求&#xff0c;达到预期的质量和性能要求。因此&#xff0c;在进行软件科技项目验收时&#xff0c;有一些注意事项需要遵循。 一、软件科技项目验收的注意事项 1、明确验收标准…

JS使用随机数生成随机验证码

一 随机数测试 在JavaScript中&#xff0c;我们可以使用random&#xff08; &#xff09;方法来生成0&#xff5e;1的一个随机数。random&#xff0c;就是“随机”的意思。需要注意的是&#xff0c;这里的0&#xff5e;1包含0但不包含1&#xff0c;也就是[0, 1&#xff09;。在…

ubuntu20.04 ROS 环境下使用velodyne激光雷达

ROS 环境下使用velodyne激光雷达 系统版本:ubuntu 20.04 ROS版本&#xff1a;noetic 激光雷达型号&#xff1a;velodyne VLP-16 1.系统环境配置 sudo apt install ros-noetic-velodyne #安装ROS依赖 mkdir-p velodyne_ws/src …

PyQt重绘事件处理函数paintEvent

PyQt中的重绘和Windows编程中的重绘差不多&#xff0c;但是Qt的重绘更有特色&#xff0c;更加智能。基础部件类QWidget提供的paintEvent函数是一个纯虚函数&#xff0c;继承它的子类想用它&#xff0c;就必须重新实现它。下列4种情况会发生重绘事件&#xff1a; &#xff08;1…

全网最全的Salesforce营销云管理员认证考点梳理!

Marketing Cloud管理员认证适用于在Marketing Cloud套件中具有设置和维护各种模块&#xff08;Studios/Builders&#xff09;和功能的经验的营销专业人员。Salesforce建议备考者拥有3到6个月的Marketing Cloud管理员和数字营销人员实践经验。 营销云管理员认证 考试内容&#…

IOS发布:App Store Connect Operation Error。SDK Version Issue.

错误描述&#xff1a; App Store Connect Operation Error SDK Version Issue. This app was built with the iOS 15.0 SDK. all iOS apps submitted to the App Store must be built with the iOS 16.1 SDK or later, included in Xcode 14.1 or later. 问题原因&#xf…

ESP32 的多种睡眠模式以及如何让 ESP32 进入深度睡眠模式

ESP32 因其 BLE 兼容性功能以及更低的成本而受到广泛关注。它还带有 32 个 GPIO 引脚和一个 32 位双核 CPU。虽然,它提供了很多功能,但在正常使用模式下似乎很耗电。当应用程序由市电供电时,没有急事,但是当它们由电池供电时,我们必须非常注意 ESP32 的功耗。 ESP32 提供…

SQL使用技巧(6)HIVE开窗函数

专题&#xff1a;SQL使用技巧——实践是检验SQL函数的唯一标准 一.构建数据二.排序开窗三.sum开窗&#xff08;重点内容&#xff09;3.1累加与求和3.2窗口表达式3.3场景模拟 四.count开窗4.1计数规则4.2计数与排序 五.max和min开窗六.lead和lag开窗七.first_value和last_value开…

RabbitMq创建交换机和队列

1. 网页登录 IP:1572 2. 输入登录账号密码 admin admin 3. 点击Exchanges 添加交换机Platform_AlarmEngineInterface 和Rg_Platform_AlarmEngineInterface &#xff0c;Type选择topic 4. 添加队列 VIDEO_Alarm_platform、watch_ftp、RG_VIDEO_Alarm_platform、RG_VIDEO_…

远程进入服务器界面黑屏如何处理?

​  远程登录服务器出现黑屏是很常见的问题&#xff0c;可能是由于多种原因引起的。但不管是哪种原因&#xff0c;当远程连接成功&#xff0c;进入桌面显示黑屏都会让用户感到困扰&#xff0c;无法正常使用服务器。下面我们将为您介绍一些常见的解决方法。 1. 重启远程桌面服…

js深拷贝和浅拷贝

&#x1f449;十分钟学会 前端面试题 js 深拷贝与浅拷贝_前端深拷贝和浅拷贝面试题_Mar-30的博客-CSDN博客 目录 背景&#xff1a; 概念&#xff1a;核心是创建新地址 方法&#xff1a; 浅拷贝&#xff1a; Object.assign() 方法&#xff1a;Object.assign(拷贝的对象&am…