命令模式:封装操作
将请求封装为 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 反馈 — 无需本地设置。
此课程中的所有课时
- 观察者模式:事件通知
- 策略模式:可互换算法
- 命令模式:封装操作
- 模板方法:定义算法骨架