JAVA设计模式之命令模式详解

news2025/1/23 2:03:27

命令模式

1 命令模式介绍

命令模式(command pattern)的定义: 命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象并且能够支持请求(命令)的排队执行、记录日志、撤销等 (附加控制)功能。

命令模式的核心是将指令信息封装成一个对象,并将此对象作为参数发送给接收方去执行,达到使命令的请求与执行方解耦,双方只通过传递各种命令对象来完成任务.

在实际的开发中,如果你用到的编程语言并不支持用函数作为参数来传递,那么就可以借助命令模式将函数封装为对象来使用。

我们知道,C 语言支持函数指针,我们可以把函数当作变量传递来传递去。但是,在大部分编程语言中,函数没法儿作为参数传递给其他函数,也没法儿赋值给变量。借助命令模式,我们可以将函数 封装成对象。具体来说就是,设计一个包含这个函数的类,实例化一个对象传来传去,这样就可以实现把函数像对象一样使用。

2 命令模式原理

在这里插入图片描述

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

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

3 命令模式实现

模拟酒店后厨的出餐流程,来对命令模式进行一个演示,命令模式角色的角色与案例中角色的对应关系如下:

  • 服务员: 即调用者角色,由她来发起命令.
  • 厨师: 接收者,真正执行命令的对象.
  • 订单: 命令中包含订单
/**
 * 订单类
 **/
public class Order {

    private int diningTable;  //餐桌号码

    //存储菜名与份数
    private Map<String,Integer> foodMenu = new HashMap<>();

    public int getDiningTable() {
        return diningTable;
    }

    public void setDiningTable(int diningTable) {
        this.diningTable = diningTable;
    }

    public Map<String, Integer> getFoodMenu() {
        return foodMenu;
    }

    public void setFoodDic(Map<String, Integer> foodMenu) {
        this.foodMenu = foodMenu;
    }
}

/**
 * 厨师类 -> Receiver角色
 **/
public class Chef {

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


/**
 * 抽象命令接口
 **/
public interface Command {

    void execute(); //只需要定义一个统一的执行方法
}

/**
 * 具体命令
 **/
public class OrderCommand implements Command {

    //持有接收者对象
    private Chef receiver;

    private Order order;

    public OrderCommand(Chef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }

    @Override
    public void execute() {
        System.out.println(order.getDiningTable() + "桌的订单: ");
        Set<String> keys = order.getFoodMenu().keySet();
        for (String key : keys) {
            receiver.makeFood(order.getFoodMenu().get(key),key);
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(order.getDiningTable() + "桌的菜已上齐.");
    }
}

/**
 * 服务员-> Invoker调用者
 **/
public class Waiter {

    //可以持有很多的命令对象
    private ArrayList<Command> commands;

    public Waiter() {
        commands = new ArrayList();
    }

    public Waiter(ArrayList<Command> commands) {
        this.commands = commands;
    }

    public void setCommands(Command command) {
        commands.add(command);
    }

    //发出命令 ,指挥厨师工作
    public void orderUp(){
        System.out.println("服务员: 叮咚,有新的订单,请厨师开始制作......");
        for (Command cmd : commands) {
            if(cmd != null){
                cmd.execute();
            }
        }
    }
}

public class Client {

    public static void main(String[] args) {

        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.getFoodMenu().put("鲍鱼炒饭",1);
        order1.getFoodMenu().put("茅台迎宾",1);

        Order order2 = new Order();
        order2.setDiningTable(3);
        order2.getFoodMenu().put("海参炒面",1);
        order2.getFoodMenu().put("五粮液",1);

        //创建接收者
        Chef receiver = new Chef();

        //将订单和接收者封装成命令对象
        OrderCommand cmd1 = new OrderCommand(receiver,order1);
        OrderCommand cmd2 = new OrderCommand(receiver,order2);

        //创建调用者
        Waiter invoke = new Waiter();
        invoke.setCommands(cmd1);
        invoke.setCommands(cmd2);

        //将订单发送到后厨
        invoke.orderUp();
    }
}

4 命令模式总结

  1. 命令模式优点:
  • 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
  • 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  1. 命令模式缺点:
  • 使用命令模式可能会导致某些系统有过多的具体命令类。
  • 系统结构更加复杂。
  1. 使用场景
  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

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

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

相关文章

Java中的IO介绍

本章内容 一 、File概念 File可以代表一个目录或者一个文件&#xff0c;并不能代表文件的内容 文件和流的区别&#xff1a;File关注的是文件本身的特征&#xff0c;如名称、路径、修改时间、大小。 流关注的是文件的内容。 二、File基本的操作 常见构造方法 | File(String p…

Spring Cloud微服务网关Zuul基础入门使用

一、概述 Zuul是从设备和网络到后端应用程序所有请求的后门&#xff0c;为内部服务提供可配置的对外URL到服务的映射关系&#xff0c;基于JVM的后端路由器。具有一下的功能&#xff1a; 认证与授权压力测试金丝雀测试动态路由负载削减静态相应处理主动流量管理 其底层是基于…

屏幕字体种类介绍

[ Script and font support in Windows ] [Windows 中的脚本和字体支持&#xff3d; 在Windows 2000 以前&#xff0c;Windows 的每个主要版本都会添加对新脚本的文本显示支持。本文介绍了每个主要版本中的更改。 Since before Windows 2000, text-display support for new scr…

ARM PAC/BTI/MTE三剑客精讲与实战

一、PAC指针认证精讲与实战 思考 1、什么是栈溢出攻击&#xff1f;什么是代码重用攻击&#xff1f;区别与联系&#xff1f; 2、栈溢出攻击的软&硬件缓解技术有哪些&#xff1f;在TF-A&OPTEE上的应用&#xff1f; 3、什么是ROP攻击&#xff1f;对ROP攻击的缓解技术&…

【医学大模型 知识增强】SMedBERT:结构化语义知识 + 医学大模型 = 显著提升大模型医学文本挖掘性能

SMedBERT&#xff1a;结构化语义知识 医学大模型 显著提升医学文本挖掘任务性能 名词解释结构化语义知识预训练语言模型医学文本挖掘任务 提出背景具体步骤提及-邻居混合注意力机制实体嵌入增强实体描述增强三元组句子增强 提及-邻居上下文建模域内词汇权重学习领域自监督任务…

Swift Combine 有序的异步操作 从入门到精通十二

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

论文阅读-面向公平性的分布式系统负载均衡机制

摘要 当一组自利的用户在分布式系统中共享多个资源时&#xff0c;我们面临资源分配问题&#xff0c;即所谓的负载均衡问题。特别地&#xff0c;负载均衡被定义为将负载分配到分布式系统的服务器上&#xff0c;以便最小化作业响应时间并提高服务器的利用率。在本文中&#xff0…

【客户端】聊聊卸载安装测试、新安装测试和覆盖安装测试(持续更新中)

程序安装一般会有&#xff1a;全新安装、卸载安装、覆盖安装这几种&#xff0c;那么安装渠道和方式就非常的多样化了。iOS可以商店安装、文件安装&#xff0c;安卓有商店安装、渠道安装、APK安装 等等。 一、不同安装方式 通常来说&#xff0c;大部分用户都会走到覆盖安装&…

微信小程序(四十二)wechat-http拦截器

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码&#xff1a; utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…

【ES】--Elasticsearch的分词器详解

目录 一、前言二、分词器原理1、常用分词器2、ik分词器模式3、指定索引的某个字段进行分词测试3.1、采用ts_match_analyzer进行分词3.2、采用standard_analyzer进行分词三、如何调整分词器1、已存在的索引调整分词器2、特别的词语不能被拆开一、前言 最近项目需求,针对客户提…

SSM+SpringBoot框架

单例bean是线程安全的吗 AOP Spring事务失效 第四种&#xff0c;在方法内部使用&#xff0c;需要用代理类调用此方法 bean生命周期 bean的循环依赖 SpringMVC执行流程 、 SpringBoot自动配置原理 Spring常见注解 MyBatis执行流程 MyBatis延迟加载 MyBatis缓存

算法刷题:复写零

复写零 .习题链接题目描述算法原理初始值步骤1步骤2我的答案: . 习题链接 复写零 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素…

C++,stl,set/mutiset详解

目录 1.set容器的构造和赋值 2.set的大小和交换 3.set的插入和删除 4.set的查找和统计 5.set和mutiset区别 6.pair对组的创建 7.set排序 1.set的内置类型指定排序规则 2.set的自定义数据类型指定排序 1.set容器的构造和赋值 #include<bits/stdc.h> using name…

Ps:统计

Ps菜单&#xff1a;文件/脚本/统计 Scripts/Statistics 统计 Statistics脚本命令提供了一种高效的方法来处理和分析大量图像&#xff0c;使用户能够自动执行复杂的图像分析任务&#xff0c;并在多个图像间应用统计学方法。这个功能极大地扩展了 Photoshop 在科学研究、图像编辑…

论文介绍 VolumeDiffusion

论文介绍 VolumeDiffusion: Flexible Text-to-3D Generation with Efficient Volumetric Encoder 关注微信公众号: DeepGo 源码地址&#xff1a; https://github.com/tzco/VolumeDiffusion 论文地址&#xff1a; https://arxiv.org/abs/2312.11459 VolumeDiffusion模型是一个从…

分享85个jQuery特效,总有一款适合您

分享85个jQuery特效&#xff0c;总有一款适合您 85个jQuery特效下载链接&#xff1a;https://pan.baidu.com/s/1-n18tdXFuTyYBvGOU94lIQ?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…

数制和码制

目录 几种常见的数制 数制 基数 位权 常见的四种数制 十进制数 二进制数 八进制数 十六进制数 不同进制数的相互转换 例如 例如 编码 二-十进制码 例如 格雷码 例如 原码、反码和补码 几种常见的数制 关键术语 数制&#xff1a;以一组固定的符号和统一的规则来表示数值…

###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 一. 两个主要软件的介绍 1.KeiluVision5软件 Keil uVision5是一款集成开发…

Vue中 常用的修饰符有哪些

Vue是一款建立在JavaScript框架上的开源前端库&#xff0c;已经成为当今前端开发人员最喜爱的选择之一。它的简洁语法和强大的功能使得开发者可以轻松地构建交互性的网页应用程序。在Vue中&#xff0c;修饰符是一个重要的概念&#xff0c;它们可以帮助我们更好地控制和定制DOM元…

python多线程连接MySQL查数案例

该博文展示地是基本示例&#xff0c;实际使用时可能需要进行调整。例如&#xff0c;你可能需要添加错误处理来确保数据库连接问题不会导致脚本崩溃&#xff0c;或者你可能需要调整查询以匹配你的数据。 此外&#xff0c;你需要确保你的系统有足够的内存和处理能力来支持并行处理…