定义
命令模式(Command Pattern) 是一种行为型设计模式,核心思想是将请求封装为独立对象(命令对象),使请求的发送者与接收者解耦。其关键特性包括:
1)请求对象化:将操作(如“打开文件”“撤销操作”)封装成包含执行方法的独立对象。
2)调用者与执行者分离:调用者(Invoker)只需调用命令对象的统一接口,无需知晓具体执行细节。
3)支持扩展操作:新增命令无需修改现有代码,符合开闭原则
结构
适用场景
1)需要参数化请求的场景,根据不同参数触发不同操作。
2)需要支持事务/撤销操作的场景,记录操作历史以便回滚。
使用示例
文本编辑器撤销功能。
定义命令接口
/**
* 命令接口(抽象命令)
*/
public interface Command {
void execute();
void undo();
}
定义具体命令
/**
* 具体命令:文本输入命令
*/
public class InsertCommand implements Command {
private StringBuilder receiver; // 接收者:文本内容
private String text; // 操作的文本
private int position; // 插入位置
public InsertCommand(StringBuilder sb, String text, int pos) {
this.receiver = sb;
this.text = text;
this.position = pos;
}
@Override
public void execute() {
receiver.insert(position, text); // 执行插入
}
@Override
public void undo() {
receiver.delete(position, position + text.length()); // 撤销:删除插入的文本
}
}
定义命令历史
import java.util.Stack;
public class CommandHistory {
private Stack<Command> undoStack = new Stack<>();
private Stack<Command> redoStack = new Stack<>();
// 记录新执行的命令
public void push(Command cmd) {
undoStack.push(cmd);
redoStack.clear(); // 新命令使重做栈失效
}
// 撤销最近操作
public boolean undo() {
if (!undoStack.isEmpty()) {
Command cmd = undoStack.pop();
cmd.undo();
redoStack.push(cmd);
return true;
}
return false;
}
// 重做最近撤销的操作
public boolean redo() {
if (!redoStack.isEmpty()) {
Command cmd = redoStack.pop();
cmd.execute();
undoStack.push(cmd);
return true;
}
return false;
}
// 清空历史记录
public void clear() {
undoStack.clear();
redoStack.clear();
}
}
定义调用者
/**
* 调用者(Invoker):编辑器界面按钮
* receiver 由java自带的StringBuilder担当
*/
public class EditorButton {
private Command command;
private CommandHistory history;
public EditorButton(CommandHistory history) {
this.history = history;
}
public void setCommand(Command cmd) {
this.command = cmd;
}
public void onClick() {
command.execute(); // 执行命令
history.push(command); // 存入历史栈
}
}
测试
public class Client {
public static void main(String[] args) {
StringBuilder textContent = new StringBuilder("Hello"); // 接收者:文本内容
CommandHistory history = new CommandHistory();
EditorButton insertBtn = new EditorButton(history);
// 创建命令:在位置5插入" World!"
insertBtn.setCommand(new InsertCommand(textContent, " World!", 5));
insertBtn.onClick(); // 执行 → 文本变为"Hello World!"
System.out.println(textContent);
history.undo(); // 撤销 → 文本恢复为"Hello"
System.out.println(textContent);
}
}