定义
Command Partern: 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。(核心思想是将"动作"与"执行者"解耦)
场景
-
GUI:操作将UI控件与业务逻辑解耦,一个命令可被多处复用。
-
撤销/重做:通过记录命令历史和状态,实现操作的回逆。
-
任务队列:实现任务的延迟执行和异步处理,解耦生产与消费。
-
宏录制:使用组合模式将多个命令组合成一个宏命令。
-
事务系统:提供原子操作和回滚机制。
-
异步回调:封装未来需要执行的操作,实现模块间的解耦通信。
Java中的典型场景
-
Swing/AWT事件处理:
ActionListener
本质是命令模式。 -
线程池:
Runnable
或Callable
任务封装了执行逻辑。 -
事务管理:数据库操作封装为可回滚的命令对象。
代码
java
import java.util.Stack;
// 文档编辑器的撤销和执行
// 命令接口
interface EditorCommand {
void execute();
void undo();
}
// 接收者:文档
class Document {
private StringBuilder content = new StringBuilder();
public String getContent() {
return content.toString();
}
public void insertText(String text) {
content.append(text);
System.out.println("插入文本: " + text + ",当前内容: " + content);
}
public void deleteText(int length) {
if (length > content.length()) {
length = content.length();
}
String deleted = content.substring(content.length() - length);
content.delete(content.length() - length, content.length());
System.out.println("删除文本: " + deleted + ",当前内容: " + content);
}
}
// 具体命令:插入文本
class InsertCommand implements EditorCommand {
private Document document;
private String text;
public InsertCommand(Document doc, String text) {
this.document = doc;
this.text = text;
}
@Override
public void execute() {
document.insertText(text);
}
@Override
public void undo() {
document.deleteText(text.length());
}
}
// 调用者:编辑器
class TextEditor {
private Stack<EditorCommand> commandHistory = new Stack<>();
private Stack<EditorCommand> redoStack = new Stack<>();
public void executeCommand(EditorCommand command) {
command.execute();
commandHistory.push(command);
redoStack.clear(); // 执行新命令后清空重做栈
}
public void undo() {
if (!commandHistory.isEmpty()) {
EditorCommand command = commandHistory.pop();
command.undo();
redoStack.push(command);
System.out.println("执行撤销操作");
} else {
System.out.println("没有可撤销的操作");
}
}
public void redo() {
if (!redoStack.isEmpty()) {
EditorCommand command = redoStack.pop();
command.execute();
commandHistory.push(command);
System.out.println("执行重做操作");
} else {
System.out.println("没有可重做的操作");
}
}
}
// 测试类
class TextEditorDemo {
public static void main(String[] args) {
Document doc = new Document();
TextEditor editor = new TextEditor();
System.out.println("=== 编辑文档过程 ===");
editor.executeCommand(new InsertCommand(doc, "Hello "));
editor.executeCommand(new InsertCommand(doc, "World "));
editor.executeCommand(new InsertCommand(doc, "Java!"));
System.out.println("\n=== 撤销操作 ===");
editor.undo(); // 撤销插入"Java!"
editor.undo(); // 撤销插入"World "
System.out.println("\n=== 重做操作 ===");
editor.redo(); // 重做插入"World "
editor.redo(); // 重做插入"Java!"
}
}
生活中的示例:文档编辑器撤销 (Undo) 和重做 (Redo) 功能,比如餐厅点餐系统的例子:服务员(调用者)接收顾客的点单(命令),然后交给厨房(接收者)执行。在比如家电遥控器:遥控器上的每个按钮都对应一个命令,按下按钮就执行相应操作(开、关、调节等)