My App

命令模式

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 按钮绑定操作

On this page