当前位置: 首页 > news >正文

Java设计模式-命令模式

Java设计模式-命令模式

模式概述

命令模式简介

核心思想:将“请求”封装为独立的命令对象,使请求的发送者(调用者)与接收者(执行者)完全解耦。通过命令对象的统一接口,支持请求的参数化、队列化、日志记录及撤销/重做等扩展操作。

模式类型:行为型设计模式(关注对象间的交互与职责分配)。

作用

  • 解耦发送者与接收者:调用者只需持有命令对象,无需直接依赖具体接收者。
  • 支持灵活扩展:新增请求类型仅需添加新的命令类,符合“开闭原则”。
  • 实现复杂控制:通过命令队列、日志记录或事务管理,支持批量执行、撤销/重做等功能。

典型应用场景

  • GUI事件处理(如按钮点击触发菜单打开、窗口关闭等操作)。
  • 事务管理系统(如数据库事务的提交/回滚,通过命令对象记录操作步骤)。
  • 智能设备控制(如遥控器控制空调、电视,通过命令对象统一管理多设备操作)。
  • 消息队列(如将用户请求封装为命令对象,异步执行或持久化存储)。

我认为:命令模式是“将动作打包成对象”的艺术,让请求的发起者专注于“触发”,执行者专注于“实现”,中间通过命令对象灵活调度。

课程目标

  • 理解命令模式的核心思想和经典应用场景
  • 识别应用场景,使用命令模式解决功能要求
  • 了解命令模式的优缺点

核心组件

角色-职责表

角色职责示例类名
命令接口(Command)定义执行请求的统一接口(如execute()Command
具体命令(ConcreteCommand)实现命令接口,绑定具体接收者并实现执行逻辑LightOnCommandLightOffCommand
调用者(Invoker)持有命令对象,触发命令执行(如遥控器按钮)RemoteController
接收者(Receiver)实际执行请求的对象(如电灯、空调等具体设备)LightAirConditioner

类图

下面是一个简化的类图表示,展示了命令模式中的主要角色及其交互方式:

实现
实现
依赖
使用
使用
«interface»
Command
+execute()
+undo()
LightOnCommand
-Light receiver
+execute()
+undo()
LightOffCommand
-Light receiver
+execute()
+undo()
RemoteController
-Command currentCommand
+setCommand(Command)
+pressButton()
+pressUndoButton()
Light
+turnOn()
+turnOff()

传统实现 VS 命令模式

案例需求

案例背景:实现一个遥控器控制电灯的功能,支持“开灯”和“关灯”操作,后续可能扩展“调节亮度”“定时开关”等新功能。

传统实现(痛点版)

代码实现

// 传统实现:调用者直接依赖接收者
class Light {public void turnOn() {System.out.println("电灯:打开");}public void turnOff() {System.out.println("电灯:关闭");}
}// 遥控器直接调用Light的方法(强耦合)
class RemoteController {private Light light;public RemoteController(Light light) {this.light = light;}public void openLight() {light.turnOn(); // 直接调用接收者方法}public void closeLight() {light.turnOff(); // 直接调用接收者方法}
}// 使用示例
public class Client {public static void main(String[] args) {Light light = new Light();RemoteController remote = new RemoteController(light);remote.openLight();  // 电灯:打开remote.closeLight(); // 电灯:关闭}
}

痛点总结

  • 强耦合:遥控器(调用者)与电灯(接收者)直接绑定,新增操作(如调节亮度)需修改遥控器代码,违反开闭原则。
  • 功能扩展困难:无法统一管理多个操作(如批量执行“开灯+关空调”),也不支持撤销/重做。
  • 缺乏抽象:请求(开灯/关灯)未被封装为对象,难以进行队列调度或日志记录。

命令模式 实现(优雅版)

代码实现

// 1. 命令接口(定义执行和撤销方法)
interface Command {void execute();  // 执行命令void undo();     // 撤销命令(可选)
}// 2. 具体命令:开灯命令(绑定接收者Light)
class LightOnCommand implements Command {private Light receiver;public LightOnCommand(Light receiver) {this.receiver = receiver;}@Overridepublic void execute() {receiver.turnOn(); // 调用接收者的实际操作}@Overridepublic void undo() {receiver.turnOff(); // 撤销操作是关灯}
}// 3. 具体命令:关灯命令
class LightOffCommand implements Command {private Light receiver;public LightOffCommand(Light receiver) {this.receiver = receiver;}@Overridepublic void execute() {receiver.turnOff();}@Overridepublic void undo() {receiver.turnOn(); // 撤销操作是开灯}
}// 4. 调用者:遥控器(支持设置和触发命令)
class RemoteController {private Command currentCommand; // 当前选中的命令public void setCommand(Command cmd) {this.currentCommand = cmd;}public void pressButton() {currentCommand.execute(); // 触发命令执行}public void pressUndoButton() {currentCommand.undo(); // 触发撤销操作}
}// 5. 接收者:电灯(实际执行操作)
class Light {public void turnOn() {System.out.println("电灯:打开");}public void turnOff() {System.out.println("电灯:关闭");}
}// 使用示例
public class Client {public static void main(String[] args) {Light light = new Light();Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);RemoteController remote = new RemoteController();remote.setCommand(lightOn);remote.pressButton();  // 输出:电灯:打开remote.setCommand(lightOff);remote.pressButton();  // 输出:电灯:关闭// 支持撤销(例如:误操作后回退)remote.setCommand(lightOn);remote.pressButton();  // 电灯:打开remote.pressUndoButton(); // 输出:电灯:关闭}
}

优势

  • 解耦调用者与接收者:遥控器(RemoteController)仅依赖Command接口,无需知道Light的具体实现。
  • 灵活扩展:新增“调节亮度”功能只需添加BrightnessAdjustCommand类,无需修改现有代码。
  • 支持复杂控制:通过命令队列(如批量执行多个命令)或日志记录(如持久化命令对象),可实现事务回滚、撤销/重做等功能。

局限

  • ​类数量增加​​:每个请求需定义一个具体命令类,可能导致系统类膨胀(可通过宏命令或组合模式优化)。
  • 过度设计风险:若需求简单(如仅需直接调用),引入命令模式会增加代码复杂度。

模式变体

  • 宏命令(Macro Command):将多个命令组合成一个复合命令(如“一键回家”场景:开灯+开空调+播放音乐),通过一次触发执行所有子命令。
  • 带事务的命令:记录命令执行前的状态(如数据库快照),通过undo()方法回滚到之前的状态,支持事务的原子性。
  • 异步命令:将命令对象放入线程池或消息队列异步执行(如电商系统中的“下单”请求,通过命令队列解耦前端与库存/支付服务)。
  • 日志命令:将命令序列化后持久化存储(如日志文件),用于系统崩溃后的恢复或操作审计。

最佳实践

建议理由
命令接口保持简洁仅定义execute()等核心方法,避免冗余方法增加实现复杂度。
接收者职责单一接收者应专注于执行具体操作(如Light仅处理电灯开关),不与命令逻辑耦合。
合理使用钩子方法在命令接口中添加可选方法(如isEnabled()),允许子类控制是否执行。
命令对象无状态若命令需频繁创建,可通过享元模式共享实例(如无状态的LightOnCommand)。
支持撤销时记录上下文undo()需要依赖执行时的状态(如修改前的数值),命令对象需保存相关上下文。

一句话总结

命令模式通过将请求封装为对象,实现了调用者与接收者的解耦,同时支持灵活扩展、批量执行及撤销/重做等高级功能,是构建可维护、可扩展系统的重要工具。

如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊

http://www.dtcms.com/a/340836.html

相关文章:

  • GitHub 热榜项目 - 日榜(2025-08-20)
  • Flask 之 Request 对象详解:全面掌握请求数据处理
  • 【NFTurbo】基于Redisson滑动窗口实现验证码发送限流
  • 如何在高并发下,保证共享数据的一致性
  • RabbitMQ的架构设计是什么样的
  • Unity 之如何使用Pico4u锚点功能实现一个世界锁GameRoot
  • 第二十七天:游戏组队问题
  • 【GPT入门】第49课 LlamaFacotory 训练千问
  • Mac电脑 Pixelmator Pro 专业图像处理【媲美PS】
  • UE5 InVideo插件打包报错
  • Linux 下实现“连 root 都无法查看和删除”的加密文件夹(附一键挂载 + 自动超时退出)
  • 【P7071 [CSP-J2020] 优秀的拆分 - 洛谷 https://www.luogu.com.cn/problem/P7071】
  • 织梦素材站网站源码 资源付费下载交易平台源码
  • 棒子出品,无须破解!
  • PyTorch API 6
  • 深度学习实战116-基于Qwen大模型与层次化对齐评分模型(HASM)的中学数学主观题自动批改系统
  • 常见开源协议详解:哪些行为被允许?哪些被限制?
  • AV1视频编码器2024-2025技术进展与行业应用分析
  • 本地部署的终极多面手:Qwen2.5-Omni-3B,视频剪、音频混、图像生、文本写全搞定
  • 第四章:大模型(LLM)】07.Prompt工程-(5)self-consistency prompt
  • PyTorch 深度学习常用函数总结
  • 使用 SSH 方式克隆 GitHub 仓库没有权限解决办法
  • [递归回溯]679. 24 点游戏
  • LINUX 820 shell:shift,expect
  • 第5.8节:awk自增自减运算
  • linux的内核符号表
  • 服装外贸系统软件怎么用才高效防风险?
  • 曲面的交线的切向量计算及其在坐标平面投影的几何分析
  • 有向图(Directed Graph)和有向无环图(Directed Acyclic Graph,DAG)代码实践
  • 反向Shell(Reverse Shell)