命令模式將請求封裝為對象,從而用不同請求參數化客戶端,支援請求排隊、日誌記錄、撤銷恢復等高級功能。它是行為請求者與執行者解耦的經典模式。
execute(),可擴展 undo()、redo()。execute() 內調用 receiver.action()。execute(),不關心具體實現。interface Command { void execute(); void undo(); }
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
public void undo() { light.off(); }
}
class RemoteControl { // 调用者
private Command command;
public void setCommand(Command cmd) { command = cmd; }
public void pressButton() { command.execute(); }
public void pressUndo() { command.undo(); }
}
// 客戶端
Light light = new Light();
Command onCmd = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(onCmd);
remote.pressButton(); // 開燈
remote.pressUndo(); // 關燈(撤銷)
將多個命令組合為宏命令,一次執行批量操作:
class MacroCommand implements Command {
private List<Command> commands;
public void execute() { commands.forEach(Command::execute); }
public void undo() { /* 逆序 undo */ }
}
| 優點 | 缺點 |
|---|---|
| 請求對象化,支援排隊、日誌、撤銷 | 命令類膨脹:每個操作一個類,簡單場景過度設計 |
| 調用者與接收者完全解耦 | 增加系統抽象層級,理解成本高 |
| 易組合宏命令,支援事務性操作 | 撤銷需接收者提供反向操作,並非所有操作可逆 |
適用場景:GUI 菜單/工具欄、多級撤銷/重做、命令隊列/異步執行、事務性操作、腳本引擎。
命令模式將「動作」變為「對象」,賦予請求一等公民地位。引入時請評估:是否真正需要撤銷/日誌/排隊?若僅為簡單封裝,普通方法即夠,切勿為模式而模式。