设计模式-命令模式
要理解设计模式中的命令模式,我们可以从其核心思想入手:将请求封装为一个对象,从而实现请求的参数化、排队、日志记录或撤销等功能。它本质上是通过“命令对象”作为中间层,解耦了“请求的发送者”和“请求的执行者”。
一、命令模式的核心角色
命令模式包含5个核心角色,各自职责如下:
| 角色 | 职责描述 |
|---|---|
| 命令接口(Command) | 声明执行操作的方法(如execute()),通常还会声明撤销操作的方法(如undo())。 |
| 具体命令(ConcreteCommand) | 实现命令接口,绑定一个“接收者”,并在execute()中调用接收者的具体操作。 |
| 接收者(Receiver) | 实际执行命令操作的对象(知道如何处理请求)。 |
| 调用者(Invoker) | 持有命令对象,负责触发命令的执行(如调用execute())。 |
| 客户端(Client) | 创建具体命令对象,绑定接收者,并将命令对象交给调用者。 |
二、Java代码演示
我们以“遥控器控制家电”为例(遥控器是调用者,家电是接收者),演示命令模式的实现。
1. 定义命令接口(Command)
声明执行和撤销的核心方法:
// 命令接口
public interface Command {
// 执行命令
void execute();
// 撤销命令
void undo();
}
2. 定义接收者(Receiver)
接收者是实际执行操作的对象(如电灯、电视):
// 电灯(接收者)
public class Light {
private String location; // 位置(如客厅、卧室)
public Light(String location) {
this.location = location;
}
// 开灯操作
public void turnOn() {
System.out.println(location + " 电灯已打开");
}
// 关灯操作
public void turnOff() {
System.out.println(location + " 电灯已关闭");
}
}
// 电视(接收者)
public class TV {
private String location;
public TV(String location) {
this.location = location;
}
// 开电视操作
public void turnOn() {
System.out.println(location + " 电视已打开");
}
// 关电视操作
public void turnOff() {
System.out.println(location + " 电视已关闭");
}
}
3. 定义具体命令(ConcreteCommand)
实现命令接口,绑定接收者并封装具体操作:
// 开灯命令
public class LightOnCommand implements Command {
private Light light; // 绑定的接收者(电灯)
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn(); // 调用电灯的“开”操作
}
@Override
public void undo() {
light.turnOff(); // 撤销:执行相反操作(关灯)
}
}
// 关灯命令
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff(); // 调用电灯的“关”操作
}
@Override
public void undo() {
light.turnOn(); // 撤销:执行相反操作(开灯)
}
}
// 开电视命令
public class TVOnCommand implements Command {
private TV tv; // 绑定的接收者(电视)
public TVOnCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOn(); // 调用电视的“开”操作
}
@Override
public void undo() {
tv.turnOff(); // 撤销:执行相反操作(关电视)
}
}
// 关电视命令
public class TVOffCommand implements Command {
private TV tv;
public TVOffCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOff(); // 调用电视的“关”操作
}
@Override
public void undo() {
tv.turnOn(); // 撤销:执行相反操作(开电视)
}
}
4. 定义调用者(Invoker)
调用者持有命令对象,并触发命令的执行(如遥控器):
// 遥控器(调用者)
public class RemoteControl {
private Command currentCommand; // 当前要执行的命令
private Command lastCommand; // 记录上一次执行的命令(用于撤销)
// 设置当前命令
public void setCommand(Command command) {
this.currentCommand = command;
}
// 按下“执行”按钮
public void pressExecuteButton() {
currentCommand.execute();
lastCommand = currentCommand; // 保存当前命令,用于后续撤销
}
// 按下“撤销”按钮
public void pressUndoButton() {
if (lastCommand != null) {
lastCommand.undo();
} else {
System.out.println("没有可撤销的命令");
}
}
}
5. 客户端(Client)测试
客户端创建对象并组装关系,模拟操作流程:
public class Client {
public static void main(String[] args) {
// 1. 创建接收者(家电)
Light livingRoomLight = new Light("客厅");
TV bedroomTV = new TV("卧室");
// 2. 创建具体命令(绑定接收者)
Command lightOn = new LightOnCommand(livingRoomLight);
Command lightOff = new LightOffCommand(livingRoomLight);
Command tvOn = new TVOnCommand(bedroomTV);
Command tvOff = new TVOffCommand(bedroomTV);
// 3. 创建调用者(遥控器)
RemoteControl remote = new RemoteControl();
// 4. 模拟操作:开客厅灯
remote.setCommand(lightOn);
remote.pressExecuteButton(); // 输出:客厅 电灯已打开
// 5. 撤销:关闭客厅灯
remote.pressUndoButton(); // 输出:客厅 电灯已关闭
// 6. 模拟操作:开卧室电视
remote.setCommand(tvOn);
remote.pressExecuteButton(); // 输出:卧室 电视已打开
// 7. 模拟操作:关卧室电视
remote.setCommand(tvOff);
remote.pressExecuteButton(); // 输出:卧室 电视已关闭
// 8. 撤销:打开卧室电视
remote.pressUndoButton(); // 输出:卧室 电视已打开
}
}
三、命令模式的优点
- 解耦发送者和接收者:调用者(如遥控器)无需知道接收者(如家电)的具体实现,只需通过命令对象间接交互。
- 易扩展:新增命令时,只需新增具体命令类,无需修改调用者或接收者(符合“开闭原则”)。
- 支持复杂操作:可实现命令排队(如批量执行)、日志记录(如记录操作历史)、撤销/重做等功能。
通过这个例子,我们可以清晰看到:命令模式将“操作请求”封装为独立的命令对象,使得请求的发送和执行完全分离,极大提升了系统的灵活性。

浙公网安备 33010602011771号