0Pricing
Java Academy · 课时

命令模式:封装操作

将请求封装为 Command 对象,以支持撤销、重做和宏录制

命令模式:封装操作 是 CoddyKit 上的免费 Java Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

Command 的意图

Command 将请求封装为对象,从而可以用不同的请求对客户端进行参数化,并支持排队、日志记录和可撤销操作。

Command 接口

定义一个包含 execute() 方法并可选包含 undo() 方法的接口。每个命令对象都知道如何执行一个操作以及如何将其撤销。

public interface Command {
    void execute();
    void undo();
}

具体命令:TextEditor

每个具体命令都会封装一个接收者和操作参数。执行时完成操作;撤销时恢复操作前的状态。

public class InsertTextCommand implements Command {
    private final TextEditor editor;
    private final String text;
    private final int position;
    public InsertTextCommand(TextEditor editor, String text, int pos) {
        this.editor = editor; this.text = text; this.position = pos;
    }
    public void execute() { editor.insert(position, text); }
    public void undo()    { editor.delete(position, text.length()); }
}

调用者:CommandHistory

调用者保存已执行命令的历史记录。它调用 execute() 并将命令压入栈中。撤销时弹出命令并调用 undo()。

public class CommandHistory {
    private final Deque<Command> history = new ArrayDeque<>();
    public void execute(Command cmd) {
        cmd.execute();
        history.push(cmd);
    }
    public void undo() {
        if (!history.isEmpty()) history.pop().undo();
    }
}

撤销/重做栈

添加一个重做栈:撤销时将命令压入重做栈;重做时从重做栈弹出命令并重新执行。

private final Deque<Command> undoStack = new ArrayDeque<>();
private final Deque<Command> redoStack = new ArrayDeque<>();
public void redo() {
    if (!redoStack.isEmpty()) {
        Command cmd = redoStack.pop();
        cmd.execute();
        undoStack.push(cmd);
    }
}

宏命令

宏命令是一种组合对象,保存命令列表并按顺序执行它们。撤销时按相反顺序执行这些操作的反向操作。

public class MacroCommand implements Command {
    private final List<Command> commands;
    public MacroCommand(List<Command> commands) { this.commands = commands; }
    public void execute() { commands.forEach(Command::execute); }
    public void undo()    { for (int i = commands.size()-1; i>=0; i--) commands.get(i).undo(); }
}

用于任务处理的命令队列

将命令存入队列并异步处理。工作线程从队列中取出并执行命令,从而将生产者与执行线程解耦。

BlockingQueue<Command> queue = new LinkedBlockingQueue<>();
// Producer:
queue.put(new SendEmailCommand(recipient, subject, body));
// Consumer thread:
Command cmd = queue.take();
cmd.execute();

使用执行器执行 Command

将命令包装为 Runnable lambda,并提交给 ExecutorService——该 lambda 就是命令对象。

ExecutorService exec = Executors.newFixedThreadPool(4);
exec.submit(() -> sendEmail(recipient, subject));
exec.submit(() -> generateReport(params));

记录命令日志以便审计

可序列化的 Command 对象可以持久化到日志中。恢复时重新执行这些命令,以重建最终状态——这正是事件溯源的基础。

void execute(Command cmd) {
    cmd.execute();
    auditLog.append(cmd.toString()); // log every action
    history.push(cmd);
}

GUI 操作按钮

在 GUI 框架中,每个按钮或菜单项都持有一个 Command。点击按钮时会调用 command.execute()。运行时替换命令,即可改变按钮的行为。

Button saveBtn = new Button("Save");
saveBtn.setOnAction(() -> new SaveDocumentCommand(doc).execute());

Command 与策略

两者都封装行为。策略封装可以在运行时替换的算法。Command 封装完整的请求,包括其参数和接收者,并支持历史记录和排队。

Spring 中的 Command

Spring 批处理模块的 Tasklet 和 Spring 集成模块的 MessageHandler 都是应用层面的命令模式。每个 Tasklet 都封装批处理作业中的一个步骤。

快速检查

为了支持撤销,Command 除了 execute() 之外还增加了哪个方法?

回顾

Command 将操作封装为对象。可以使用它实现撤销/重做栈、任务队列、宏录制和审计日志。将它与维护命令历史记录的调用者结合使用。

常见问题解答

「命令模式:封装操作」课时是免费的吗?

是的 — 「命令模式:封装操作」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「命令模式:封装操作」这节课中我会学到什么?

将请求封装为 Command 对象,以支持撤销、重做和宏录制 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「命令模式:封装操作」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 观察者模式:事件通知
  2. 策略模式:可互换算法
  3. 命令模式:封装操作
  4. 模板方法:定义算法骨架
← 返回 Java Academy