Java设计模式-命令模式
Java设计模式-命令模式
模式概述
命令模式简介
核心思想:将“请求”封装为独立的命令对象,使请求的发送者(调用者)与接收者(执行者)完全解耦。通过命令对象的统一接口,支持请求的参数化、队列化、日志记录及撤销/重做等扩展操作。
模式类型:行为型设计模式(关注对象间的交互与职责分配)。
作用:
- 解耦发送者与接收者:调用者只需持有命令对象,无需直接依赖具体接收者。
- 支持灵活扩展:新增请求类型仅需添加新的命令类,符合“开闭原则”。
- 实现复杂控制:通过命令队列、日志记录或事务管理,支持批量执行、撤销/重做等功能。
典型应用场景:
- GUI事件处理(如按钮点击触发菜单打开、窗口关闭等操作)。
- 事务管理系统(如数据库事务的提交/回滚,通过命令对象记录操作步骤)。
- 智能设备控制(如遥控器控制空调、电视,通过命令对象统一管理多设备操作)。
- 消息队列(如将用户请求封装为命令对象,异步执行或持久化存储)。
我认为:命令模式是“将动作打包成对象”的艺术,让请求的发起者专注于“触发”,执行者专注于“实现”,中间通过命令对象灵活调度。
课程目标
- 理解命令模式的核心思想和经典应用场景
- 识别应用场景,使用命令模式解决功能要求
- 了解命令模式的优缺点
核心组件
角色-职责表
角色 | 职责 | 示例类名 |
---|---|---|
命令接口(Command) | 定义执行请求的统一接口(如execute() ) | Command |
具体命令(ConcreteCommand) | 实现命令接口,绑定具体接收者并实现执行逻辑 | LightOnCommand 、LightOffCommand |
调用者(Invoker) | 持有命令对象,触发命令执行(如遥控器按钮) | RemoteController |
接收者(Receiver) | 实际执行请求的对象(如电灯、空调等具体设备) | Light 、AirConditioner |
类图
下面是一个简化的类图表示,展示了命令模式中的主要角色及其交互方式:
传统实现 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设计模式系列文章。😊