命令模式
简介
定义: 将一个请求封装为一个对象,从而可以用不同的请求对客户进行参数化。将请求封装成对象,将动作请求者和动作执行者解耦。
使用场景:
GUI按钮和菜单
撤销/重做功能
事务系统
线程池(Runnable)
实现要点:
命令对象持有接收者引用
支持撤销操作
支持宏命令
UML
代码示例
一些电器
//空调
public class AirConditioner {
private String location;
private boolean isOn = false;
private int temperature = 26;
public AirConditioner(String location) {
this.location = location;
}
public void on() {
isOn = true;
System.out.println("❄️ " + location + "的空调打开了 (温度: " + temperature + "°C)");
}
public void off() {
isOn = false;
System.out.println("❄️ " + location + "的空调关闭了");
}
public void setTemperature(int temperature) {
this.temperature = temperature;
System.out.println("❄️ " + location + "的空调温度设置为: " + temperature + "°C");
}
public boolean isOn() {
return isOn;
}
public int getTemperature() {
return temperature;
}
}
//电灯
public class Light {
private String location;
private int brightness = 0; // 亮度 0-100
public Light(String location) {
this.location = location;
}
public void on() {
brightness = 100;
System.out.println("💡 " + location + "的灯打开了 (亮度: " + brightness + "%)");
}
public void off() {
brightness = 0;
System.out.println("💡 " + location + "的灯关闭了");
}
public void dim(int level) {
brightness = level;
System.out.println("💡 " + location + "的灯调暗至: " + level + "%");
}
public int getBrightness() {
return brightness;
}
public String getLocation() {
return location;
}
}
//电视
public class TV {
private String location;
private boolean isOn = false;
private int channel = 1;
private int volume = 10;
public TV(String location) {
this.location = location;
}
public void on() {
isOn = true;
System.out.println("📺 " + location + "的电视打开了 (频道: " + channel + ", 音量: " + volume + ")");
}
public void off() {
isOn = false;
System.out.println("📺 " + location + "的电视关闭了");
}
public void setChannel(int channel) {
this.channel = channel;
System.out.println("📺 " + location + "的电视切换到频道: " + channel);
}
public void setVolume(int volume) {
this.volume = volume;
System.out.println("📺 " + location + "的电视音量设置为: " + volume);
}
public boolean isOn() {
return isOn;
}
public int getChannel() {
return channel;
}
public int getVolume() {
return volume;
}
}
命令接口
public interface Command {
/**
* 执行命令
*/
void execute();
/**
* 撤销命令
*/
void undo();
/**
* 获取命令描述
*/
String getDescription();
}命令的实现
//开空调命令 - 具体命令类
public class AirConditionerOnCommand implements Command {
private AirConditioner ac;
public AirConditionerOnCommand(AirConditioner ac) {
this.ac = ac;
}
@Override
public void execute() {
ac.on();
ac.setTemperature(24);
}
@Override
public void undo() {
ac.off();
}
@Override
public String getDescription() {
return "打开空调并设置温度";
}
}
//关灯命令 - 具体命令类
public class LightOffCommand implements Command {
private Light light;
private int previousBrightness;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
previousBrightness = light.getBrightness();
light.off();
}
@Override
public void undo() {
if (previousBrightness > 0) {
light.dim(previousBrightness);
}
}
@Override
public String getDescription() {
return "关闭" + light.getLocation() + "的灯";
}
}
//开灯命令 - 具体命令类
public class LightOnCommand implements Command {
private Light light;
private int previousBrightness;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
previousBrightness = light.getBrightness();
light.on();
}
@Override
public void undo() {
if (previousBrightness == 0) {
light.off();
} else {
light.dim(previousBrightness);
}
}
@Override
public String getDescription() {
return "打开" + light.getLocation() + "的灯";
}
}
//宏命令 - 批量执行多个命令
public class MacroCommand implements Command {
private Command[] commands;
private String description;
public MacroCommand(Command[] commands, String description) {
this.commands = commands;
this.description = description;
}
@Override
public void execute() {
System.out.println("🎯 执行宏命令: " + description);
for (Command command : commands) {
command.execute();
}
}
@Override
public void undo() {
System.out.println("↩️ 撤销宏命令: " + description);
// 倒序撤销
for (int i = commands.length - 1; i >= 0; i--) {
commands[i].undo();
}
}
@Override
public String getDescription() {
return description;
}
}
//空命令 - 用于初始化,避免空指针
public class NoCommand implements Command {
@Override
public void execute() {
// 什么都不做
}
@Override
public void undo() {
// 什么都不做
}
@Override
public String getDescription() {
return "空命令";
}
}
//关电视命令 - 具体命令类
public class TVOffCommand implements Command {
private TV tv;
public TVOffCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.off();
}
@Override
public void undo() {
tv.on();
}
@Override
public String getDescription() {
return "关闭电视";
}
}
//开电视命令 - 具体命令类
public class TVOnCommand implements Command {
private TV tv;
public TVOnCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.on();
}
@Override
public void undo() {
tv.off();
}
@Override
public String getDescription() {
return "打开电视";
}
}
命令控制器
public class RemoteControl {
/**
* 遥控器有7个插槽,每个插槽可以设置一个命令
*/
private Command[] onCommands;
private Command[] offCommands;
/**
* 撤销命令栈
*/
private Stack<Command> undoStack;
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
undoStack = new Stack<>();
// 初始化为空命令,避免空指针
Command noCommand = new NoCommand();
for (int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
/**
* 设置命令
*/
public void setCommand(int slot, Command onCommand, Command offCommand) {
if (slot >= 0 && slot < 7) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
}
/**
* 按下ON按钮
*/
public void onButtonWasPressed(int slot) {
if (slot >= 0 && slot < 7) {
System.out.println("\n🔘 按下ON按钮 [插槽" + slot + "]");
onCommands[slot].execute();
undoStack.push(onCommands[slot]);
}
}
/**
* 按下OFF按钮
*/
public void offButtonWasPressed(int slot) {
if (slot >= 0 && slot < 7) {
System.out.println("\n🔘 按下OFF按钮 [插槽" + slot + "]");
offCommands[slot].execute();
undoStack.push(offCommands[slot]);
}
}
/**
* 按下撤销按钮
*/
public void undoButtonWasPressed() {
if (!undoStack.isEmpty()) {
System.out.println("\n↩️ 按下撤销按钮");
Command command = undoStack.pop();
command.undo();
} else {
System.out.println("\n❌ 没有可撤销的命令");
}
}
/**
* 显示遥控器状态
*/
public void showStatus() {
System.out.println("\n📱 ===== 遥控器状态 =====");
for (int i = 0; i < 7; i++) {
System.out.println("[插槽" + i + "] ON: " + onCommands[i].getDescription() +
" | OFF: " + offCommands[i].getDescription());
}
System.out.println("========================");
}
}
使用方式
public class Test {
public static void main(String[] args) {
System.out.println("=== 命令模式 - 智能家居遥控器示例 ===\n");
// ========== 创建接收者(家电设备) ==========
Light livingRoomLight = new Light("客厅");
Light bedroomLight = new Light("卧室");
TV livingRoomTV = new TV("客厅");
AirConditioner livingRoomAC = new AirConditioner("客厅");
// ========== 创建命令对象 ==========
// 灯光命令
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
LightOnCommand bedroomLightOn = new LightOnCommand(bedroomLight);
LightOffCommand bedroomLightOff = new LightOffCommand(bedroomLight);
// 电视命令
TVOnCommand tvOn = new TVOnCommand(livingRoomTV);
TVOffCommand tvOff = new TVOffCommand(livingRoomTV);
// 空调命令
AirConditionerOnCommand acOn = new AirConditionerOnCommand(livingRoomAC);
// ========== 创建遥控器(调用者) ==========
RemoteControl remote = new RemoteControl();
// 设置命令到遥控器插槽
remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remote.setCommand(1, bedroomLightOn, bedroomLightOff);
remote.setCommand(2, tvOn, tvOff);
remote.setCommand(3, acOn, acOn); // 空调使用同一个命令
// 显示遥控器状态
remote.showStatus();
// ========== 场景1:基本命令执行 ==========
System.out.println("\n【场景1:基本命令执行】");
// 打开客厅灯
remote.onButtonWasPressed(0);
// 关闭客厅灯
remote.offButtonWasPressed(0);
// 打开卧室灯
remote.onButtonWasPressed(1);
// 打开电视
remote.onButtonWasPressed(2);
// ========== 场景2:撤销命令 ==========
System.out.println("\n\n【场景2:撤销命令】");
// 打开空调
remote.onButtonWasPressed(3);
// 撤销(关闭空调)
remote.undoButtonWasPressed();
// 再次撤销(打开电视被撤销,即关闭电视)
remote.undoButtonWasPressed();
// ========== 场景3:宏命令(批量执行) ==========
System.out.println("\n\n【场景3:宏命令 - 回家模式】");
// 创建"回家模式"宏命令:打开客厅灯、打开电视、打开空调
Command[] partyOnCommands = {
livingRoomLightOn,
tvOn,
acOn
};
MacroCommand partyOnMacro = new MacroCommand(partyOnCommands, "回家模式");
// 创建"离家模式"宏命令:关闭所有设备
Command[] partyOffCommands = {
livingRoomLightOff,
bedroomLightOff,
tvOff
};
MacroCommand partyOffMacro = new MacroCommand(partyOffCommands, "离家模式");
// 将宏命令设置到遥控器
remote.setCommand(6, partyOnMacro, partyOffMacro);
// 执行"回家模式"
remote.onButtonWasPressed(6);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行"离家模式"
System.out.println();
remote.offButtonWasPressed(6);
// 撤销"离家模式"
System.out.println();
remote.undoButtonWasPressed();
// ========== 总结 ==========
System.out.println("\n\n=== 命令模式说明 ===");
System.out.println("1. 命令接口: Command - 定义执行和撤销方法");
System.out.println("2. 具体命令: LightOnCommand等 - 封装请求为对象");
System.out.println("3. 接收者: Light、TV等 - 真正执行操作的对象");
System.out.println("4. 调用者: RemoteControl - 持有命令并触发执行");
System.out.println("5. 客户端: 创建命令对象并设置接收者");
System.out.println("\n=== 命令模式优势 ===");
System.out.println("✅ 解耦: 调用者与接收者解耦");
System.out.println("✅ 可扩展: 易于添加新命令");
System.out.println("✅ 可撤销: 支持undo/redo操作");
System.out.println("✅ 可组合: 支持宏命令(组合多个命令)");
System.out.println("✅ 可记录: 可以记录命令历史");
System.out.println("✅ 可队列: 可以将命令放入队列执行");
System.out.println("\n=== 命令模式应用场景 ===");
System.out.println("📌 GUI按钮/菜单: 将用户操作封装为命令");
System.out.println("📌 事务系统: 支持回滚的事务操作");
System.out.println("📌 宏命令: 批量执行多个操作");
System.out.println("📌 任务调度: 将任务封装为命令放入队列");
System.out.println("📌 日志系统: 记录操作历史");
System.out.println("📌 撤销/重做: 编辑器、绘图软件等");
System.out.println("📌 线程池: 将任务封装为Runnable命令");
System.out.println("\n=== 命令模式的关键点 ===");
System.out.println("🔑 将请求封装为对象");
System.out.println("🔑 命令对象持有接收者引用");
System.out.println("🔑 调用者只知道命令接口,不知道具体实现");
System.out.println("🔑 支持撤销操作(保存状态)");
System.out.println("🔑 支持宏命令(命令的组合)");
System.out.println("\n=== 命令模式在Java中的应用 ===");
System.out.println("🔸 Runnable接口: 将任务封装为命令");
System.out.println("🔸 Swing/JavaFX: ActionListener封装按钮动作");
System.out.println("🔸 Spring: ApplicationEvent命令模式应用");
System.out.println("🔸 数据库事务: 可回滚的操作");
}
}
Last updated
Was this helpful?