淺學設計模式之命令模式(22/23)

1. 命令模式的概念

命令模式(Command),將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操作。

命令模式是行爲型設計模式之一。我們接觸比較多的命令模式個例無非就是程序菜單命令,如在操作系統中,我們點擊“關機”命令,系統就會去執行一系列的操作,如先是暫停處理事件,保存系統的一些配置,然後結束程序進程,最後調用內核命令關閉計算機等,對於這一系列的命令,用戶不用去管,用戶只需只需點擊系統的關機按鈕即可完成如上一系列的命令。而我們的命令模式其實也與之相同,將一系列的方法調用封裝,用戶只需調用一個方法執行,那麼所有這些被封裝的方法就會被挨個執行。

命令模式的使用場景:

  • 需要抽象處待執行的動作,然後以參數的形式提供出來—類似於過程設計中的回調機制,而命令模式正是回調機制的一個面向對象的替代品
  • 在不同的時刻指定、排列和執行請求。一個命令對象可以有與初始請求無關的生存期。
  • 需要支持取消操作
  • 支持修改日誌功能,這樣當系統崩潰時,這些修改可以被重做一遍。
  • 需要支持事務操作。

2. UML圖

來看下命令模式的UML圖:
在這裏插入圖片描述
它有如下的角色

  • Receiver接受者角色
    該類負責具體實施或執行一個請求,說的通俗一點就是,執行具體邏輯的角色,以本章開頭的“關機”命令操作爲例,其接受者角色就是真正執行各項關機邏輯的低層代碼。任何一個類都可以成爲一個接受者,而在接受者類中封裝具體操作邏輯的方法我們則成爲行動方法。
  • Command命令角色
    定義了所有具體命令類的抽象接口
  • ConcreteCommand具體命令角色
    該類實現了Command接口,在execute()方法中調用接收者角色的相關方法,在接收者和命令執行的具體行爲之間加以耦合。而execute則通常稱爲執行方法,如本文開頭的“關機”的操作實現,具體可能還包含很多的相關操作,比如保存數據、關閉文件、結束進程等,如果將這一系列具體的邏輯處理看做接收者,那麼調用這些具體邏輯的方法就可以看做是執行方法。
  • Invoker請求者角色
    該類的職責就是調用命令對象執行具體的請求,相關的方法我們成爲行動方法,還是用“關機”爲例,我們點擊了關機後,由這個關機方法去調用具體的命令執行具體的邏輯,這裏的“關機”對應的這個方法就可以看作是請求者。

來看下代碼的實現:
接收者類:

class Receiver{
    /**
     * 真正執行具體命令邏輯的方法
     */
    public void action() {
        System.out.println("執行具體操作");
    }
}

命令接口類:

interface Command {
    /**
     * 執行具體的操作
     */
    void execute();
}

具體命令類,實現命令接口:

class ConcreteCommand implements Command {
    // 持有一個對接收者對象的引用
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        // 調用接收者的相關方法來執行具體的邏輯
        receiver.action();
    }
}

請求者類:

class Invoker {
    //持有一個或多個相應命令對象的引用
    private Command command;

    public Invoker(Command command) {
        this.command = command;
    }
    
    public void action() {
        // 調用具體命令對象的相關方法,執行具體命令
        command.execute();
    }
}

最後是客戶端類:

class CommandMain {
    public static void main(String[] args) {
        // 構造一個接收者對象
        Receiver receiver = new Receiver();
        
        // 根據接收者對象構造一個命令對象
        Command command = new ConcreteCommand(receiver);
        
        // 根據具體的對象構造請求者對象
        Invoker invoker = new Invoker(command);
        
        // 執行請求方法
        invoker.action();
    }
}

這樣執行後,我們執行了 Invoker的方法,就不用管後續的一系列的操作了,最終命令會使得Reciver來執行。

3. 小結

在命令模式中,其充分體現了幾乎所有設計模式的通病,就是類的膨脹,大量衍生類的創建,這是一個不可避免的問題,但是,其給我們帶來的好處也是非常多,更弱的耦合性、更靈活的控制性以及更好的可擴展性,不過,在實際開發過程中,是不是需要採用命令模式還是需要斟酌。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章