文章目录
-
- 什么是命令模式?
- 核心思想
- 生活中的命令模式
- 模式结构
- 基础示例:智能家居系统
-
- [1. 命令接口](#1. 命令接口)
- [2. 接收者 - 家电设备](#2. 接收者 - 家电设备)
- [3. 具体命令类](#3. 具体命令类)
- [4. 调用者 - 遥控器](#4. 调用者 - 遥控器)
- [5. 客户端使用](#5. 客户端使用)
- 完整示例:文本编辑器
-
- [1. 文本编辑器接收者](#1. 文本编辑器接收者)
- [2. 编辑器命令](#2. 编辑器命令)
- [3. 编辑器调用者](#3. 编辑器调用者)
- [4. 文本编辑器客户端](#4. 文本编辑器客户端)
- 命令模式的优点
-
- [1. 解耦调用者和接收者](#1. 解耦调用者和接收者)
- [2. 支持撤销和重做](#2. 支持撤销和重做)
- [3. 支持命令队列和日志](#3. 支持命令队列和日志)
- 命令模式的缺点
-
- [1. 可能产生大量命令类](#1. 可能产生大量命令类)
- [2. 增加系统复杂度](#2. 增加系统复杂度)
- 适用场景
- 最佳实践
-
- [1. 使用宏命令](#1. 使用宏命令)
- [2. 实现空对象](#2. 实现空对象)
- [3. 考虑命令的生命周期](#3. 考虑命令的生命周期)
- [命令模式 vs 其他模式](#命令模式 vs 其他模式)
- 总结
什么是命令模式?
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
核心思想
命令模式的核心思想是:将请求封装成对象,使得可以用不同的请求对客户端进行参数化,并支持请求的排队、记录、撤销等操作。
生活中的命令模式
想象一下餐厅的点餐流程:
- 顾客(客户端)创建订单(命令对象)
- 服务员(调用者)接收订单并交给厨房
- 厨师(接收者)根据订单准备食物
- 订单可以取消、修改或重复使用
订单就是命令对象!
模式结构
命令模式包含五个核心角色:
- 命令接口(Command):声明执行操作的接口
- 具体命令(Concrete Command):实现命令接口,绑定接收者和动作
- 接收者(Receiver):知道如何执行请求的具体操作
- 调用者(Invoker):要求命令执行请求
- 客户端(Client):创建具体命令并设置接收者
基础示例:智能家居系统
1. 命令接口
java
/**
* 命令接口 - 声明执行操作的接口
*/
public interface Command {
/**
* 执行命令
*/
void execute();
/**
* 撤销命令
*/
void undo();
/**
* 获取命令描述
*/
String getDescription();
}
2. 接收者 - 家电设备
java
/**
* 电灯 - 接收者
* 知道如何执行具体的操作
*/
public class Light {
private final String location;
private boolean isOn;
private int brightness; // 亮度级别 0-100
public Light(String location) {
this.location = location;
this.isOn = false;
this.brightness = 50; // 默认亮度
System.out.println("💡 初始化电灯: " + location);
}
public void turnOn() {
this.isOn = true;
System.out.println("💡 " + location + " 电灯已打开");
}
public void turnOff() {
this.isOn = false;
System.out.println("💡 " + location + " 电灯已关闭");
}
public void setBrightness(int level) {
if (level < 0) level = 0;
if (level > 100) level = 100;
this.brightness = level;
System.out.println("💡 " + location + " 亮度设置为: " + level + "%");
}
public void dim() {
setBrightness(brightness - 10);
}
public void brighten() {
setBrightness(brightness + 10);
}
public boolean isOn() {
return isOn;
}
public int getBrightness() {
return brightness;
}
public String getStatus() {
return String.format("电灯[%s] - 状态: %s, 亮度: %d%%",
location, isOn ? "开" : "关", brightness);
}
}
/**
* 空调 - 接收者
*/
public class AirConditioner {
private final String location;
private boolean isOn;
private int temperature;
private String mode; // 制冷/制热/送风
public AirConditioner(String location) {
this.location = location;
this.isOn = false;
this.temperature = 26;
this.mode = "制冷";
System.out.println("❄️ 初始化空调: " + location);
}
public void turnOn() {
this.isOn = true;
System.out.println("❄️ " + location + " 空调已打开");
}
public void turnOff() {
this.isOn = false;
System.out.println("❄️ " + location + " 空调已关闭");
}
public void setTemperature(int temperature) {
this.temperature = temperature;
System.out.println("❄️ " + location + " 温度设置为: " + temperature + "°C");
}
public void setMode(String mode) {
this.mode = mode;
System.out.println("❄️ " + location + " 模式设置为: " + mode);
}
public boolean isOn() {
return isOn;
}
public String getStatus() {
return String.format("空调[%s] - 状态: %s, 温度: %d°C, 模式: %s",
location, isOn ? "开" : "关", temperature, mode);
}
}
/**
* 电视 - 接收者
*/
public class Television {
private final String location;
private boolean isOn;
private int volume;
private int channel;
public Television(String location) {
this.location = location;
this.isOn = false;
this.volume = 20;
this.channel = 1;
System.out.println("📺 初始化电视: " + location);
}
public void turnOn() {
this.isOn = true;
System.out.println("📺 " + location + " 电视已打开");
}
public void turnOff() {
this.isOn = false;
System.out.println("📺 " + location + " 电视已关闭");
}
public void setVolume(int volume) {
this.volume = volume;
System.out.println("📺 " + location + " 音量设置为: " + volume);
}
public void setChannel(int channel) {
this.channel = channel;
System.out.println("📺 " + location + " 频道切换到: " + channel);
}
public void volumeUp() {
setVolume(volume + 5);
}
public void volumeDown() {
setVolume(volume - 5);
}
public void channelUp() {
setChannel(channel + 1);
}
public void channelDown() {
setChannel(channel - 1);
}
public boolean isOn() {
return isOn;
}
public String getStatus() {
return String.format("电视[%s] - 状态: %s, 频道: %d, 音量: %d",
location, isOn ? "开" : "关", channel, volume);
}
}
3. 具体命令类
java
/**
* 电灯开关命令 - 具体命令
*/
public class LightOnCommand implements Command {
private final Light light;
private int previousBrightness;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
previousBrightness = light.getBrightness();
light.turnOn();
light.setBrightness(80); // 默认打开时设置合适亮度
}
@Override
public void undo() {
light.turnOff();
light.setBrightness(previousBrightness);
}
@Override
public String getDescription() {
return "打开电灯: " + light.getStatus();
}
}
/**
* 电灯关闭命令
*/
public class LightOffCommand implements Command {
private final Light light;
private int previousBrightness;
private boolean wasOn;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
wasOn = light.isOn();
previousBrightness = light.getBrightness();
light.turnOff();
}
@Override
public void undo() {
if (wasOn) {
light.turnOn();
light.setBrightness(previousBrightness);
}
}
@Override
public String getDescription() {
return "关闭电灯: " + light.getStatus();
}
}
/**
* 电灯调光命令
*/
public class LightDimCommand implements Command {
private final Light light;
private int previousBrightness;
public LightDimCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
previousBrightness = light.getBrightness();
light.dim();
}
@Override
public void undo() {
light.setBrightness(previousBrightness);
}
@Override
public String getDescription() {
return "调暗电灯: " + light.getStatus();
}
}
/**
* 空调开关命令
*/
public class AirConditionerOnCommand implements Command {
private final AirConditioner airConditioner;
private int previousTemperature;
private String previousMode;
private boolean wasOn;
public AirConditionerOnCommand(AirConditioner airConditioner) {
this.airConditioner = airConditioner;
}
@Override
public void execute() {
wasOn = airConditioner.isOn();
previousTemperature = 26; // 简化处理
previousMode = "制冷";
airConditioner.turnOn();
airConditioner.setTemperature(24);
airConditioner.setMode("制冷");
}
@Override
public void undo() {
if (!wasOn) {
airConditioner.turnOff();
}
// 在实际应用中,应该恢复之前的设置
}
@Override
public String getDescription() {
return "打开空调: " + airConditioner.getStatus();
}
}
/**
* 电视开关命令
*/
public class TelevisionOnCommand implements Command {
private final Television television;
private int previousVolume;
private int previousChannel;
private boolean wasOn;
public TelevisionOnCommand(Television television) {
this.television = television;
}
@Override
public void execute() {
wasOn = television.isOn();
previousVolume = television.isOn() ? television.getStatus().length() : 20; // 简化
previousChannel = 1;
television.turnOn();
television.setChannel(1);
television.setVolume(25);
}
@Override
public void undo() {
if (!wasOn) {
television.turnOff();
}
}
@Override
public String getDescription() {
return "打开电视: " + television.getStatus();
}
}
/**
* 宏命令 - 同时执行多个命令
*/
public class MacroCommand implements Command {
private final List<Command> commands;
private final String name;
public MacroCommand(String name, Command... commands) {
this.name = name;
this.commands = new ArrayList<>(Arrays.asList(commands));
}
public void addCommand(Command command) {
commands.add(command);
}
@Override
public void execute() {
System.out.println("🎮 执行宏命令: " + name);
for (Command command : commands) {
command.execute();
}
}
@Override
public void undo() {
System.out.println("↩️ 撤销宏命令: " + name);
// 按相反顺序撤销
for (int i = commands.size() - 1; i >= 0; i--) {
commands.get(i).undo();
}
}
@Override
public String getDescription() {
return "宏命令[" + name + "] - 包含 " + commands.size() + " 个操作";
}
}
4. 调用者 - 遥控器
java
import java.util.Stack;
/**
* 智能遥控器 - 调用者
* 负责触发命令的执行
*/
public class SmartRemoteControl {
private final Map<String, Command> commandSlots;
private final Stack<Command> commandHistory;
private Command lastCommand;
public SmartRemoteControl() {
this.commandSlots = new HashMap<>();
this.commandHistory = new Stack<>();
this.lastCommand = null;
System.out.println("🎛️ 初始化智能遥控器");
}
/**
* 设置命令到指定槽位
*/
public void setCommand(String slot, Command command) {
commandSlots.put(slot, command);
System.out.println("📝 设置命令到槽位 [" + slot + "]: " + command.getDescription());
}
/**
* 按下按钮执行命令
*/
public void pressButton(String slot) {
Command command = commandSlots.get(slot);
if (command != null) {
System.out.println("\n🔘 按下按钮: " + slot);
command.execute();
commandHistory.push(command);
lastCommand = command;
} else {
System.out.println("❌ 未找到槽位: " + slot);
}
}
/**
* 撤销上一个命令
*/
public void pressUndo() {
if (!commandHistory.isEmpty()) {
Command command = commandHistory.pop();
System.out.println("\n↩️ 执行撤销操作");
command.undo();
} else {
System.out.println("❌ 没有可撤销的命令");
}
}
/**
* 显示遥控器状态
*/
public void displayStatus() {
System.out.println("\n📋 遥控器状态:");
System.out.println("-".repeat(50));
commandSlots.forEach((slot, command) -> {
System.out.printf("🔘 %-15s -> %s%n", slot, command.getDescription());
});
System.out.printf("📜 命令历史: %d 个命令%n", commandHistory.size());
}
/**
* 清除命令历史
*/
public void clearHistory() {
commandHistory.clear();
System.out.println("🗑️ 清除命令历史");
}
}
5. 客户端使用
java
/**
* 智能家居客户端
*/
public class SmartHomeClient {
public static void main(String[] args) {
System.out.println("=== 命令模式演示 - 智能家居系统 ===\n");
// 创建接收者 - 家电设备
Light livingRoomLight = new Light("客厅");
Light bedroomLight = new Light("卧室");
AirConditioner livingRoomAC = new AirConditioner("客厅");
Television livingRoomTV = new Television("客厅");
// 创建命令
Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
Command livingRoomLightOff = new LightOffCommand(livingRoomLight);
Command livingRoomLightDim = new LightDimCommand(livingRoomLight);
Command livingRoomACOn = new AirConditionerOnCommand(livingRoomAC);
Command livingRoomTVOn = new TelevisionOnCommand(livingRoomTV);
// 创建宏命令
MacroCommand eveningMode = new MacroCommand("晚间模式",
livingRoomLightOn, livingRoomTVOn);
MacroCommand leaveHomeMode = new MacroCommand("离家模式",
livingRoomLightOff, new LightOffCommand(bedroomLight));
// 创建调用者 - 遥控器
SmartRemoteControl remote = new SmartRemoteControl();
// 配置遥控器
remote.setCommand("灯开", livingRoomLightOn);
remote.setCommand("灯关", livingRoomLightOff);
remote.setCommand("调光", livingRoomLightDim);
remote.setCommand("空调", livingRoomACOn);
remote.setCommand("电视", livingRoomTVOn);
remote.setCommand("晚间", eveningMode);
remote.setCommand("离家", leaveHomeMode);
// 显示遥控器状态
remote.displayStatus();
// 演示1:基础命令执行
demonstrateBasicCommands(remote);
// 演示2:撤销功能
demonstrateUndoFeature(remote);
// 演示3:宏命令
demonstrateMacroCommands(remote);
// 演示4:命令队列
demonstrateCommandQueue();
}
/**
* 演示基础命令执行
*/
private static void demonstrateBasicCommands(SmartRemoteControl remote) {
System.out.println("\n1. 基础命令执行演示:");
System.out.println("=" .repeat(40));
remote.pressButton("灯开");
remote.pressButton("调光");
remote.pressButton("电视");
remote.pressButton("空调");
}
/**
* 演示撤销功能
*/
private static void demonstrateUndoFeature(SmartRemoteControl remote) {
System.out.println("\n2. 撤销功能演示:");
System.out.println("=" .repeat(40));
remote.pressButton("灯关");
remote.pressUndo(); // 应该重新打开灯
remote.pressButton("调光");
remote.pressButton("调光");
remote.pressUndo(); // 撤销一次调光
remote.pressUndo(); // 再撤销一次调光
}
/**
* 演示宏命令
*/
private static void demonstrateMacroCommands(SmartRemoteControl remote) {
System.out.println("\n3. 宏命令演示:");
System.out.println("=" .repeat(40));
System.out.println("执行晚间模式:");
remote.pressButton("晚间");
System.out.println("\n执行离家模式:");
remote.pressButton("离家");
System.out.println("\n撤销离家模式:");
remote.pressUndo();
}
/**
* 演示命令队列
*/
private static void demonstrateCommandQueue() {
System.out.println("\n4. 命令队列演示:");
System.out.println("=" .repeat(40));
CommandProcessor processor = new CommandProcessor();
Light kitchenLight = new Light("厨房");
Television kitchenTV = new Television("厨房");
processor.addCommand(new LightOnCommand(kitchenLight));
processor.addCommand(new TelevisionOnCommand(kitchenTV));
processor.addCommand(new LightDimCommand(kitchenLight));
System.out.println("处理命令队列...");
processor.processCommands();
}
}
/**
* 命令处理器 - 支持命令队列
*/
class CommandProcessor {
private final Queue<Command> commandQueue;
public CommandProcessor() {
this.commandQueue = new LinkedList<>();
}
public void addCommand(Command command) {
commandQueue.offer(command);
System.out.println("📥 添加命令到队列: " + command.getDescription());
}
public void processCommands() {
System.out.println("🔄 开始处理命令队列...");
while (!commandQueue.isEmpty()) {
Command command = commandQueue.poll();
System.out.println("⚡ 执行: " + command.getDescription());
command.execute();
try {
Thread.sleep(500); // 模拟处理时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("✅ 所有命令处理完成");
}
}
完整示例:文本编辑器
让我们通过一个更复杂的文本编辑器示例来深入理解命令模式。
1. 文本编辑器接收者
java
import java.util.ArrayList;
import java.util.List;
/**
* 文本编辑器 - 接收者
* 知道如何执行文本操作
*/
public class TextEditor {
private StringBuilder content;
private int cursorPosition;
private List<String> clipboard;
public TextEditor() {
this.content = new StringBuilder();
this.cursorPosition = 0;
this.clipboard = new ArrayList<>();
System.out.println("📝 初始化文本编辑器");
}
public void insertText(String text) {
content.insert(cursorPosition, text);
cursorPosition += text.length();
System.out.println("📝 插入文本: \"" + text + "\"");
displayContent();
}
public void deleteText(int length) {
if (cursorPosition >= length) {
int start = cursorPosition - length;
String deleted = content.substring(start, cursorPosition);
content.delete(start, cursorPosition);
cursorPosition = start;
System.out.println("🗑️ 删除文本: \"" + deleted + "\"");
displayContent();
}
}
public void copyText(int start, int end) {
if (start >= 0 && end <= content.length() && start < end) {
String copied = content.substring(start, end);
clipboard.add(copied);
System.out.println("📋 复制文本: \"" + copied + "\"");
}
}
public void pasteText() {
if (!clipboard.isEmpty()) {
String textToPaste = clipboard.get(clipboard.size() - 1);
insertText(textToPaste);
}
}
public void setCursorPosition(int position) {
if (position >= 0 && position <= content.length()) {
this.cursorPosition = position;
System.out.println("📍 光标位置设置为: " + position);
}
}
public void boldText(int start, int end) {
if (start >= 0 && end <= content.length() && start < end) {
content.insert(end, "**");
content.insert(start, "**");
cursorPosition = end + 2;
System.out.println("🔷 加粗文本范围: " + start + "-" + end);
displayContent();
}
}
public void undoInsert(int position, int length) {
content.delete(position, position + length);
cursorPosition = position;
displayContent();
}
public void undoDelete(int position, String text) {
content.insert(position, text);
cursorPosition = position + text.length();
displayContent();
}
public String getContent() {
return content.toString();
}
public int getCursorPosition() {
return cursorPosition;
}
public void displayContent() {
String display = content.toString();
if (display.length() > 50) {
display = display.substring(0, 47) + "...";
}
System.out.println("📄 内容: \"" + display + "\" [光标位置: " + cursorPosition + "]");
}
public void displayFullContent() {
System.out.println("📄 完整内容: \"" + content.toString() + "\"");
}
}
2. 编辑器命令
java
/**
* 插入文本命令
*/
public class InsertTextCommand implements Command {
private final TextEditor editor;
private final String text;
private int insertPosition;
public InsertTextCommand(TextEditor editor, String text) {
this.editor = editor;
this.text = text;
}
@Override
public void execute() {
insertPosition = editor.getCursorPosition();
editor.insertText(text);
}
@Override
public void undo() {
editor.undoInsert(insertPosition, text.length());
}
@Override
public String getDescription() {
return "插入文本: \"" + text + "\"";
}
}
/**
* 删除文本命令
*/
public class DeleteTextCommand implements Command {
private final TextEditor editor;
private final int length;
private int deletePosition;
private String deletedText;
public DeleteTextCommand(TextEditor editor, int length) {
this.editor = editor;
this.length = length;
}
@Override
public void execute() {
deletePosition = editor.getCursorPosition() - length;
if (deletePosition >= 0) {
int end = editor.getCursorPosition();
deletedText = editor.getContent().substring(deletePosition, end);
editor.deleteText(length);
}
}
@Override
public void undo() {
if (deletedText != null) {
editor.undoDelete(deletePosition, deletedText);
}
}
@Override
public String getDescription() {
return "删除 " + length + " 个字符";
}
}
/**
* 复制文本命令
*/
public class CopyTextCommand implements Command {
private final TextEditor editor;
private final int start;
private final int end;
public CopyTextCommand(TextEditor editor, int start, int end) {
this.editor = editor;
this.start = start;
this.end = end;
}
@Override
public void execute() {
editor.copyText(start, end);
}
@Override
public void undo() {
// 复制操作通常不需要撤销
System.out.println("⚠️ 复制操作不可撤销");
}
@Override
public String getDescription() {
return "复制文本范围: " + start + "-" + end;
}
}
/**
* 粘贴文本命令
*/
public class PasteTextCommand implements Command {
private final TextEditor editor;
private int pastePosition;
private String pastedText;
public PasteTextCommand(TextEditor editor) {
this.editor = editor;
}
@Override
public void execute() {
pastePosition = editor.getCursorPosition();
// 这里简化处理,实际应该从剪贴板获取
pastedText = "已复制的文本";
editor.pasteText();
}
@Override
public void undo() {
if (pastedText != null) {
editor.undoInsert(pastePosition, pastedText.length());
}
}
@Override
public String getDescription() {
return "粘贴文本";
}
}
/**
* 加粗文本命令
*/
public class BoldTextCommand implements Command {
private final TextEditor editor;
private final int start;
private final int end;
public BoldTextCommand(TextEditor editor, int start, int end) {
this.editor = editor;
this.start = start;
this.end = end;
}
@Override
public void execute() {
editor.boldText(start, end);
}
@Override
public void undo() {
// 简化处理,实际应该记录更详细的状态
System.out.println("↩️ 撤销加粗操作");
}
@Override
public String getDescription() {
return "加粗文本: " + start + "-" + end;
}
}
3. 编辑器调用者
java
import java.util.Stack;
/**
* 文本编辑器控制器 - 调用者
*/
public class EditorController {
private final TextEditor editor;
private final Stack<Command> history;
private final Stack<Command> redoStack;
public EditorController(TextEditor editor) {
this.editor = editor;
this.history = new Stack<>();
this.redoStack = new Stack<>();
System.out.println("🎮 初始化编辑器控制器");
}
public void executeCommand(Command command) {
command.execute();
history.push(command);
redoStack.clear(); // 执行新命令时清空重做栈
System.out.println("✅ 执行: " + command.getDescription());
}
public void undo() {
if (!history.isEmpty()) {
Command command = history.pop();
command.undo();
redoStack.push(command);
System.out.println("↩️ 撤销: " + command.getDescription());
} else {
System.out.println("❌ 没有可撤销的操作");
}
}
public void redo() {
if (!redoStack.isEmpty()) {
Command command = redoStack.pop();
command.execute();
history.push(command);
System.out.println("↪️ 重做: " + command.getDescription());
} else {
System.out.println("❌ 没有可重做的操作");
}
}
public void showHistory() {
System.out.println("\n📜 操作历史:");
System.out.println("-".repeat(40));
for (int i = 0; i < history.size(); i++) {
System.out.printf("%2d. %s%n", i + 1, history.get(i).getDescription());
}
}
public void showEditorStatus() {
System.out.println("\n📊 编辑器状态:");
editor.displayFullContent();
}
}
4. 文本编辑器客户端
java
/**
* 文本编辑器客户端
*/
public class TextEditorClient {
public static void main(String[] args) {
System.out.println("=== 命令模式演示 - 文本编辑器 ===\n");
// 创建接收者
TextEditor editor = new TextEditor();
// 创建调用者
EditorController controller = new EditorController(editor);
// 演示1:基础文本操作
demonstrateBasicOperations(controller, editor);
// 演示2:撤销重做功能
demonstrateUndoRedo(controller);
// 演示3:复杂操作序列
demonstrateComplexOperations(controller, editor);
// 显示最终状态
controller.showEditorStatus();
controller.showHistory();
}
private static void demonstrateBasicOperations(EditorController controller, TextEditor editor) {
System.out.println("1. 基础文本操作演示:");
System.out.println("=" .repeat(40));
controller.executeCommand(new InsertTextCommand(editor, "Hello, "));
controller.executeCommand(new InsertTextCommand(editor, "Command Pattern!"));
controller.executeCommand(new InsertTextCommand(editor, " 这是一个命令模式的演示。"));
// 设置光标位置并删除
editor.setCursorPosition(7); // 移动到 "Hello, " 后面
controller.executeCommand(new DeleteTextCommand(editor, 8)); // 删除 "Command"
}
private static void demonstrateUndoRedo(EditorController controller) {
System.out.println("\n2. 撤销重做功能演示:");
System.out.println("=" .repeat(40));
System.out.println("撤销两次操作:");
controller.undo();
controller.undo();
System.out.println("\n重做一次操作:");
controller.redo();
System.out.println("\n再次撤销:");
controller.undo();
}
private static void demonstrateComplexOperations(EditorController controller, TextEditor editor) {
System.out.println("\n3. 复杂操作序列演示:");
System.out.println("=" .repeat(40));
// 插入新内容
controller.executeCommand(new InsertTextCommand(editor, "\n\n新段落开始。"));
controller.executeCommand(new InsertTextCommand(editor, " 这是重要内容。"));
// 复制和粘贴(简化演示)
editor.setCursorPosition(0);
controller.executeCommand(new CopyTextCommand(editor, 0, 5));
controller.executeCommand(new PasteTextCommand(editor));
// 加粗文本
controller.executeCommand(new BoldTextCommand(editor, 10, 15));
System.out.println("\n执行多次撤销:");
for (int i = 0; i < 3; i++) {
controller.undo();
}
}
}
命令模式的优点
1. 解耦调用者和接收者
java
// 调用者不需要知道接收者的具体细节
// 只需要知道如何触发命令
2. 支持撤销和重做
java
// 命令对象可以保存状态
// 很容易实现撤销/重做功能
3. 支持命令队列和日志
java
// 可以轻松实现命令队列
// 支持命令的延迟执行和日志记录
命令模式的缺点
1. 可能产生大量命令类
java
// 每个操作都需要一个命令类
// 可能导致类的数量增加
2. 增加系统复杂度
java
// 引入了额外的抽象层
// 对于简单操作可能过于复杂
适用场景
- 需要支持撤销/重做操作时
- 需要将操作参数化时
- 需要支持命令队列或日志时
- 需要支持事务操作时
最佳实践
1. 使用宏命令
java
// 将多个命令组合成一个宏命令
// 支持批量操作
2. 实现空对象
java
// 实现一个空命令对象
// 避免空指针检查
3. 考虑命令的生命周期
java
// 对于需要长时间运行的命令
// 考虑实现取消功能
命令模式 vs 其他模式
| 模式 | 目的 | 特点 |
|---|---|---|
| 命令模式 | 封装请求 | 支持撤销、队列、参数化 |
| 策略模式 | 封装算法 | 算法可以互相替换 |
| 责任链模式 | 处理请求 | 多个对象可以处理请求 |
总结
命令模式就像是"任务委托书",把请求打包成对象,让它们可以被传递、存储和执行。
核心价值:
- 将请求封装成对象
- 支持撤销和重做操作
- 支持命令队列和日志
- 解耦请求发送者和接收者
使用场景:
- 需要实现撤销/重做功能时
- 需要将操作参数化时
- 需要支持事务操作时
简单记忆:
请求太多难管理?命令模式来解决!
打包成对象,撤销重做都容易。
掌握命令模式,能够让你构建出支持复杂操作流程的系统,提供更好的用户体验!