引言:软件设计的解耦艺术
在软件开发中,我们常面临请求发起者与请求执行者之间的紧密耦合问题。这种耦合会导致:
- 系统扩展困难:新增命令需要修改现有代码
- 功能复用受限:相同操作无法在不同上下文中重用
- 撤销/重做复杂:操作历史难以追踪和管理
命令模式正是为解决这类问题而生的设计模式。它将请求封装成独立对象,允许你参数化客户端使用不同的请求、队列或日志请求,并支持可撤销的操作。本文将深入解析命令模式的原理、实现及高级应用场景。
一、模式定义与核心思想
1.1 官方定义
命令模式 (Command Pattern):将请求封装成对象,从而让你使用不同的请求、队列或日志请求来参数化其他对象,并支持可撤销的操作。
1.2 设计哲学
核心原则:
- 解耦调用与执行:调用者无需知道接收者细节
- 命令对象化:将操作封装为可传递的对象
- 支持扩展:新增命令不影响现有系统结构
二、模式结构解析
2.1 UML类图
classDiagram
class Invoker {
-command: Command
+setCommand(Command)
+executeCommand()
}
interface Command {
<<interface>>
+execute()
+undo()
}
class ConcreteCommand {
-receiver: Receiver
-state
+execute()
+undo()
}
class Receiver {
+action()
}
Invoker o--> Command
Command <|.. ConcreteCommand
ConcreteCommand --> Receiver
2.2 关键角色
角色 | 职责 | 示例 |
---|---|---|
Invoker | 触发命令执行 | 遥控器按钮 |
Command | 声明执行接口 | 命令接口 |
ConcreteCommand | 实现具体命令 | 开灯命令 |
Receiver | 实际执行操作 | 电灯设备 |
三、代码实战:智能家居控制系统
3.1 场景描述
实现智能家居控制系统:
- 控制多种设备:灯、空调、音响
- 支持单命令执行和宏命令(组合命令)
- 实现撤销操作功能
3.2 核心实现
// 命令接口
public interface Command {
void execute();
void undo();
}
// 接收者:电灯
public class Light {
public void on() {
System.out.println("电灯已打开");
}
public void off() {
System.out.println("电灯已关闭");
}
}
// 具体命令:开灯命令
public class LightOnCommand implements Command {
private final Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
// 接收者:空调
public class AirConditioner {
private int temperature = 26;
public void setTemperature(int temp) {
this.temperature = temp;
System.out.println("空调温度设置为: " + temp + "℃");
}
public int getTemperature() {
return temperature;
}
}
// 具体命令:设置空调温度
public class SetTemperatureCommand implements Command {
private final AirConditioner ac;
private final int newTemperature;
private int prevTemperature;
public SetTemperatureCommand(AirConditioner ac, int temperature) {
this.ac = ac;
this.newTemperature = temperature;
}
@Override
public void execute() {
prevTemperature = ac.getTemperature();
ac.setTemperature(newTemperature);
}
@Override
public void undo</