探讨命令模式及其应用
目录
- 命令模式
- 命令模式结构
- 命令模式适用场景
- 命令模式优缺点
- 练手题目
- 题目描述
- 输入描述
- 输出描述
- 题解
命令模式
命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
命令模式结构
- 发送者(Sender)——亦称 “触发者(Invoker)”——类负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。发送者触发命令,而不向接收者直接发送请求。注意,发送者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令。
- 命令(Command)接口通常仅声明一个执行命令的方法。
- 具体命令 (Concrete Commands)会实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象。但为了简化代码,这些类可以进行合并。接收对象执行方法所需的参数可以声明为具体命令的成员变量。你可以将命令对象设为不可变,仅允许通过构造函数对这些成员变量进行初始化。
- 接收者(Receiver)类包含部分业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。
- 客户端(Client)会创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联了。
命令模式通用代码:
//抽象接收者
public abstract class Receiver{public abstract void operation();
}//具体接收者
public class Recevier1 extends Recevier{public void operation(){...}
}//通用命令接口
public interface Command{void execute();
}//具体命令类
public class ConcreteCommand1 implements Command{private Receiver receiver;public ConcreteCommand1(Receiver _receiver){this.receiver = _receiver;}public void execute(){this.receiver.operation();}
}//调用者类
public class Invoker{private Command command;public void setCommand(Command _command){this.command = _command;}public void executeCommand(){this.command.execute();}}//主程序类
public class Client{public static void main(String[] args){//调用者Invoker invoker = new Invoker();//接收者Receiver receiver1 = new Receiver1();//定义一个命令Command command = new ConcreteCommand1(receiver1);invoker.setCommand(command);invoker.executeCommand();}
}
命令模式适用场景
-
如果你需要通过操作来参数化对象,可使用命令模式。
命令模式可将特定的方法调用转化为独立对象。 这一改变也带来了许多有趣的应用: 你可以将命令作为方法的参数进行传递、 将命令保存在其他对象中, 或者在运行时切换已连接的命令等。
-
如果你想要将操作放入队列中、操作的执行或者远程执行操作,可使用命令模式。
同其他对象一样,命令也可以实现序列化(序列化的意思是转化为字符串),从而能方便地写入文件或数据库中。一段时间后,该字符串可被恢复成为最初的命令对象。因此,你可以延迟或计划命令的执行。但其功能远不止如此!使用同样的方式,你还可以将命令放入队列、记录命令或者通过网络发送命令。
-
如果你想要实现操作回滚功能,可使用命令模式。
**识别方法:**命令模式可以通过抽象或接口类型(发送者)中的行为方法来识别, 该类型调用另一个不同的抽象或接口类型 (接收者)实现中的方法,该实现则是在创建时由命令模式的实现封装。命令类通常仅限于一些特殊行为。
命令模式优缺点
命令模式优点:
- 单一职责原则。你可以解耦触发和执行操作的类。
- 开闭原则。你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
- 你可以实现撤销和恢复功能。
- 你可以实现操作的延迟执行。
- 你可以将一组简单命令组合成一个复杂命令。
命令模式缺点:
- 代码可能会变得更加复杂,因为你在发送者和接收者之间增加了一个全新的层次。
练手题目
题目描述
小明去奶茶店买奶茶,他可以通过在自助点餐机上来点不同的饮品,请你使用命令模式设计一个程序,模拟这个自助点餐系统的功能。
输入描述
第一行是一个整数 n(1 ≤ n ≤ 100),表示点单的数量。
接下来的 n 行,每行包含一个字符串,表示点餐的饮品名称。
输出描述
输出执行完所有点单后的制作情况,每行输出一种饮品的制作情况。如果制作完成,输出 “XXX is ready!”,其中 XXX 表示饮品名称。
题解
解法一:
import java.util.Scanner;// 枚举类表示饮料类型
enum BeverageType {MILKTEA, COFFEE, COLA
}// 抽象饮料类
abstract class Beverage {abstract void make();
}// 具体饮料类
class MilkTea extends Beverage {@Overridepublic void make() {System.out.println("MilkTea is ready!");}
}class Coffee extends Beverage {@Overridepublic void make() {System.out.println("Coffee is ready!");}
}class Cola extends Beverage {@Overridepublic void make() {System.out.println("Cola is ready!");}
}// 抽象命令类
abstract class Command {protected Beverage beverage;public Command(Beverage _beverage) {this.beverage = _beverage;}abstract void execute();
}// 具体命令类
class MilkTeaCommand extends Command {public MilkTeaCommand() {super(new MilkTea());}@Overridepublic void execute() {beverage.make();}
}class CoffeeCommand extends Command {public CoffeeCommand() {super(new Coffee());}@Overridepublic void execute() {beverage.make();}
}class ColaCommand extends Command {public ColaCommand() {super(new Cola());}@Overridepublic void execute() {beverage.make();}
}// 调用者类
class Invoker {private Command command;public void setCommand(Command _command) {command = _command;}public void action() {command.execute();}
}// 主类
public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);try {Invoker invoker = new Invoker();int n = scanner.nextInt();scanner.nextLine();for (int i = 0; i < n; i++) {String type = scanner.nextLine().trim().toUpperCase();try {switch (BeverageType.valueOf(type)) {case MILKTEA:invoker.setCommand(new MilkTeaCommand());break;case COFFEE:invoker.setCommand(new CoffeeCommand());break;case COLA:invoker.setCommand(new ColaCommand());break;default:System.out.println("请重新输入:");continue;}invoker.action();} catch (IllegalArgumentException e) {System.out.println("无效的饮料类型");}}} catch (Exception e) {System.out.println("发生错误: " + e.getMessage());} finally {scanner.close();}}
}
解法二:
import java.util.Scanner;// 命令接口
interface Command {void execute();
}// 具体命令类 - 点餐命令
class OrderCommand implements Command {private String drinkName;private DrinkMaker receiver;public OrderCommand(String drinkName, DrinkMaker receiver) {this.drinkName = drinkName;this.receiver = receiver;}@Overridepublic void execute() {receiver.makeDrink(drinkName);}
}// 接收者类 - 制作饮品
class DrinkMaker {public void makeDrink(String drinkName) {System.out.println(drinkName + " is ready!");}
}// 调用者类 - 点餐机
class OrderMachine {private Command command;public void setCommand(Command command) {this.command = command;}public void executeOrder() {command.execute();}
}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 创建接收者和命令对象DrinkMaker drinkMaker = new DrinkMaker();// 读取命令数量int n = scanner.nextInt();scanner.nextLine();while (n-- > 0) {// 读取命令String drinkName = scanner.next();// 创建命令对象Command command = new OrderCommand(drinkName, drinkMaker);// 执行命令OrderMachine orderMachine = new OrderMachine();orderMachine.setCommand(command);orderMachine.executeOrder();}scanner.close();}
}
解法三:命令模式+工厂模式
import java.util.Scanner;// 命令接口
interface Command {void execute();
}// 具体命令类 - 点餐命令
class OrderCommand implements Command {private String drinkName;private DrinkMaker receiver;public OrderCommand(String drinkName, DrinkMaker receiver) {this.drinkName = drinkName;this.receiver = receiver;}@Overridepublic void execute() {receiver.makeDrink(drinkName);}
}// 接收者类 - 制作饮品
class DrinkMaker {public void makeDrink(String drinkName) {System.out.println(drinkName + " is ready!");}
}// 调用者类 - 点餐机
class OrderMachine {private Command command;public void setCommand(Command command) {this.command = command;}public void executeOrder() {if (command != null) {command.execute();} else {System.out.println("未设置命令.");}}
}// 命令工厂类
class CommandFactory {private DrinkMaker drinkMaker;public CommandFactory(DrinkMaker drinkMaker) {this.drinkMaker = drinkMaker;}public Command createCommand(String drinkName) {return new OrderCommand(drinkName, drinkMaker);}
}// 主类
public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 创建接收者和工厂对象DrinkMaker drinkMaker = new DrinkMaker();CommandFactory commandFactory = new CommandFactory(drinkMaker);OrderMachine orderMachine = new OrderMachine();// 读取命令数量int n = scanner.nextInt();scanner.nextLine();while (n-- > 0) {// 读取命令String drinkName = scanner.nextLine().trim();if (drinkName.isEmpty()) {System.out.println("无效输入,请输入饮品名.");continue;}// 使用工厂创建命令对象Command command = commandFactory.createCommand(drinkName);// 设置命令并执行orderMachine.setCommand(command);orderMachine.executeOrder();}scanner.close();}
}
相关文章:

探讨命令模式及其应用
目录 命令模式命令模式结构命令模式适用场景命令模式优缺点练手题目题目描述输入描述输出描述题解 命令模式 命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其…...

1、音视频解封装流程---解复用
对于一个视频文件(mp4格式/flv格式),audio_pkt或者video_pkt是其最基本的数据单元,即视频文件是由独立的视频编码包或者音频编码包组成的。 解复用就是从视频文件中把视频包/音频包单独读取出来保存成独立文件,那么如何得知packet是视频包还是…...
centos7升级gcc到7.3.0
1、下载gcc-7.3.0源码 wget ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.gz 2、解压gcc-7.3.0 tar -xvf gcc-7.3.0.tar.gz3、安装依赖 cd gcc-7.3.0 ./contrib/download_prerequisites ./contrib/download_prerequisites会下载对应的依赖包,如果下载不了的话&a…...

系统运维面试题总结(网络基础类)
系统运维面试题总结(网络基础类) 网络基础类第七层:应用层第六层:表示层第五层:会话层第四层:传输层第三层:网络层第二层:数据链路层第一层:物理层 类似面试题1、TCP/IP四…...

PO模式登录测试
项目实践 登陆项目测试 get_driver import page from selenium import webdriverclass GetDriver:driver Noneclassmethoddef get_driver(cls):if cls.driver is None:cls.driver webdriver.Edge()cls.driver.maximize_window()cls.driver.get(page.url)return cls.drivercl…...

X86 +PC104+支持WinCE5.0,WinCE6.0,DOS,WinXP, QNX等操作系统,工业控制数据采集核心模块板卡定制
CPU 模块 是一款基于RDC 3306的SOM Express模块。RDC 3306这款X86架构的CPU是一款性能高、稳定性强的处理器。 它是一款灵活精巧的主板(尺寸为91.8mm68.6mm),可以灵活的运用于用户的底板,节约开发成本。模块的接插件使用插针形式…...

视频监控汇聚和融合平台的特点、功能、接入方式、应用场景
目录 一、产品概述 二、主要特点 1、多协议支持 2、高度集成与兼容性 3、高性能与可扩展性 4、智能化分析 5、安全可靠 三、功能概述 1. 视频接入与汇聚 2. 视频存储与回放 3. 实时监控与预警 4. 信息共享与联动 5. 远程管理与控制 四、接入方式 1、直接接入 2…...

实习总结 --- 其他业务
一. 回归测试:回归测试与测新是对应的,当需求准入交付测试的时候首先要进行的就是测新,也就是对新功能对测试,一般是在sim环境下测试的;当测新通过后才会进行回归测试,回归测试的目的是为了保证老功能的正确…...

2024年上半年典型网络攻击事件汇总
文章目录 前言一、Ivanti VPN 的0 Day攻击(2024年1月)二、微软公司高管账户泄露攻击(2024年1月)三、Change Healthcare网络攻击(2024年2月)四、ConnectWise ScreenConnect漏洞利用攻击(2024年2月)五、XZ Utils软件供应链攻击(2024年3月)六、AT&T数据泄露攻击(20…...

Ozon、美客多补单测评黑科技:打造无懈可击的自养号补单环境
不管哪个跨境平台的风控都会做升级,相对的补单技术也需要进行相应的做升级,风控升级后,自己养号补单需要注意以下技术问题,以确保补单的稳定性和安全性: 一、物理环境 1. 硬件参数伪装:平台已经开始通过I…...
ES报错:解决too_many_clauses: maxClauseCount is set to 1024 报错问题
解决too_many_clauses: maxClauseCount is set to 1024 报错问题 问题场景报错信息问题分析解决1. 优化查询2. 增加maxClauseCount3. 改用其他查询类型修改后的查询示例 问题场景 查询语句:查询clcNo分类号包含分类O的所有文档 {"match_phrase_prefix":…...
完全指南:在Linux上安装和精通Conda
前言 Conda是一个强大的包管理和环境管理工具,特别适用于数据科学和机器学习项目。本文将详细指导你在Linux系统上安装、配置和充分利用Conda的方法。 步骤一:下载和安装Conda 下载安装包: wget https://repo.anaconda.com/miniconda/Minic…...

# linux 系统中,使用 “ ll “ 命令报错 “ bash ll command not found “ 解决方法:
linux 系统中,使用 " ll " 命令报错 " bash ll command not found " 解决方法: 一、错误描述: 报错原因: 1、这个错误表明你尝试在 bash shell 中执行 ll 命令,但是系统找不到这个命令。ll 通常…...

吴恩达深度学习笔记:机器学习策略(2)(ML Strategy (2)) 2.3-2.4
目录 第三门课 结构化机器学习项目(Structuring Machine Learning Projects)第二周:机器学习策略(2)(ML Strategy (2))2.3 快速搭建你的第一个系统,并进行迭代(Build your first system quickly…...

【软件测试】快速定位bug,编写测试用例
作为一名测试人员如果连常见的系统问题都不知道如何分析,频繁将前端人员问题指派给后端人员,后端人员问题指派给前端人员,那么在团队里你在开发中的地位显而易见 ,口碑、升值、加薪那应该是你遥不可及的梦 但是作为测试人员来说&…...
升级springboot3
坑爹的发版流水线,管天管地,springboot2过了维护期,就催着我们升级。 导致必须上jdk17 记录一下升级需要处理的事情 先升级springboot和cloud,这里定下基调,其他的才好跟着升级 https://spring.io/projects/spring-b…...

视频编解码从H.264到H.266:浅析GB28181安防视频汇聚EasyCVR视频压缩技术
随着信息技术的飞速发展,视频编解码技术也在不断革新,以适应高清、超高清甚至8K视频时代的到来。视频编解码技术作为数字多媒体领域的核心技术之一,也在不断地演进和革新。从早期的H.261到现在的H.265、H.266,每一次技术的升级都极…...
vue项目访问 域名/index.html 空页面问题
很大可能是vue前端没做404页面,在路由不匹配时会跳转到空路由页面。 也可以把所有路由不匹配的网址全部跳转到域名首页。防止出现404或者页面错误。 如果使用docker nginx部署项目,配置文件上会有 try_files $uri $uri/ /index.html; 这段配置会尝试…...
区块链开发入门:基础概念与实施技术详解
区块链开发入门:基础概念与实施技术详解 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 引言 随着区块链技术的快速发展,它已经不再局…...
Rust破界:前端革新与Vite重构的深度透视(下)
Rust破界:前端革新与Vite重构的深度透视(下) 前端开发者:拥抱 Rust 的策略与时机技能树的扩展 结语:跨界融合的未来展望Vite 重构的深远意义 附录:进一步探索 Rust 的资源指南 前端开发者:拥抱 …...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...