一、核心定義與設計思想
命令模式通過對象化請求,將操作的具體實現細節封裝在命令對象中,使得調用者(Invoker)無需直接依賴接收者(Receiver),僅需通過命令對象間接調用。這種設計支持以下能力:
- 解耦請求發送者與執行者:調用者僅與命令接口交互,無需了解接收者的實現細節。
- 支持擴展性與靈活性:新增命令只需實現接口,符合開閉原則。
- 實現高級功能:如撤銷(Undo)、重做(Redo)、事務管理及日志記錄。
二、模式結構與角色
命令模式包含以下核心角色:
- Command(抽象命令接口)
聲明執行操作的統一接口,通常包含execute()
方法,部分場景擴展undo()
方法以支持撤銷。public interface Command { void execute(); void undo(); // 可選 }
- ConcreteCommand(具體命令類)
實現命令接口,持有接收者的引用并調用其方法。例如:public class LightOnCommand implements Command {private Light receiver;public LightOnCommand(Light receiver) { this.receiver = receiver; }public void execute() { receiver.turnOn(); } }
- Receiver(接收者)
實際執行操作的對象,例如電燈、文本編輯器等業務邏輯實現類。 - Invoker(調用者)
觸發命令執行的入口,不關心命令具體實現。例如遙控器或按鈕:public class RemoteControl {private Command command;public void pressButton() { command.execute(); } }
- Client(客戶端)
創建具體命令對象并綁定接收者,將其傳遞給調用者。
三、代碼示例與實現
場景:遙控器控制家電(經典案例)
- 定義接收者
class Light {public void turnOn() { System.out.println("燈已開啟"); }public void turnOff() { System.out.println("燈已關閉"); } }
- 實現具體命令
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) { this.light = light; }public void execute() { light.turnOn(); } }
- 調用者與客戶端交互
結果:調用者與接收者完全解耦,支持靈活替換命令。public class Client {public static void main(String[] args) {Light light = new Light();Command cmdOn = new LightOnCommand(light);RemoteControl control = new RemoteControl();control.setCommand(cmdOn);control.pressButton(); // 輸出:燈已開啟} }
四、高級應用場景
- 撤銷與重做(Undo/Redo)
通過維護命令歷史棧實現操作回滾。例如文本編輯器的撤銷功能:class Editor {private String text;public void insert(String content) { /* 實現 */ }public void delete(String content) { /* 實現 */ } } class InsertCommand implements Command {private Editor receiver;private String content;public void execute() { receiver.insert(content); }public void undo() { receiver.delete(content); } }
- 宏命令(Macro Command)
將多個命令組合為一個復合命令,實現批量操作:class MacroCommand implements Command {private List commands = new ArrayList<>();public void add(Command cmd) { commands.add(cmd); }public void execute() { commands.forEach(Command::execute); } }
- 異步任務隊列
結合線程池處理異步請求,提升系統吞吐量:class CommandQueue {private BlockingQueue queue = new LinkedBlockingQueue<>();public void addCommand(Command cmd) { queue.put(cmd); }public void process() { queue.forEach(cmd -> new Thread(cmd::execute).start()); } }
五、優缺點分析
優點 | 缺點 |
---|---|
解耦請求發送者與接收者,提升系統靈活性 | 可能導致類爆炸問題(每個操作需獨立命令類) |
支持撤銷、重做及事務管理,增強用戶體驗 | 增加系統復雜度,需額外維護命令對象 |
符合開閉原則,擴展性強 | 過度設計風險,簡單場景可能不必要 |
六、適用場景
- GUI事件處理:如按鈕點擊、菜單操作。
- 事務性操作:數據庫事務的提交與回滾。
- 日志與審計:記錄操作歷史以便恢復。
- 異步任務調度:如消息隊列中的任務處理。
七、與其他模式的對比
- 策略模式:關注算法替換,而命令模式關注請求封裝。
- 觀察者模式:通過訂閱-發布解耦,命令模式通過對象化請求解耦。
- 責任鏈模式:請求逐級傳遞,命令模式明確單一行執行路徑。
總結
命令模式通過對象化請求實現了高度解耦與靈活控制,是構建可擴展系統的利器。其核心價值在于將操作抽象為對象,支持復雜功能(如撤銷、異步隊列)的同時降低系統耦合度。實際應用中需根據場景權衡復雜性,避免濫用。