命令模式
Command — 把请求封装成对象,支持撤销、队列、日志
一句话理解
把"做一件事"封装成一个命令对象,这样就可以对命令进行排队、撤销、重做、记录日志等操作。
解决什么问题
- 想把"发出请求"和"执行请求"解耦
- 需要支持撤销(undo)/ 重做(redo)
- 需要把操作放入队列延迟执行或记录操作日志
怎么写
以"文本编辑器的撤销功能"为例:
// 命令接口
public interface Command {
void execute();
void undo();
}
// 接收者:实际执行操作的对象
public class TextEditor {
private StringBuilder content = new StringBuilder();
public void append(String text) { content.append(text); }
public void deleteLast(int count) {
content.delete(content.length() - count, content.length());
}
public String getContent() { return content.toString(); }
}
// 具体命令:输入文字
public class TypeCommand implements Command {
private final TextEditor editor;
private final String text;
public TypeCommand(TextEditor editor, String text) {
this.editor = editor;
this.text = text;
}
public void execute() { editor.append(text); }
public void undo() { editor.deleteLast(text.length()); }
}
// 调用者:管理命令的执行和撤销
public class CommandManager {
private final Stack<Command> history = new Stack<>();
public void execute(Command cmd) {
cmd.execute();
history.push(cmd);
}
public void undo() {
if (!history.isEmpty()) {
history.pop().undo();
}
}
}TextEditor editor = new TextEditor();
CommandManager manager = new CommandManager();
manager.execute(new TypeCommand(editor, "Hello "));
manager.execute(new TypeCommand(editor, "World"));
System.out.println(editor.getContent()); // Hello World
manager.undo();
System.out.println(editor.getContent()); // Hello
manager.undo();
System.out.println(editor.getContent()); // (空)使用场景
- 编辑器的 undo/redo(VS Code、Word)
- 任务队列/消息队列
- 宏录制(把一系列操作录制下来批量回放)
- 事务回滚
- GUI 按钮绑定操作