【圖解設計模式系列】The Command Pattern: 命令列模式

Tech In Pieces發表於2020-12-29

命令模式是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令

仔細想一下 這不就是命令列的底層實現嘛?自己之前一直都在使用命令列,而從來沒有想過到底是怎麼實現的,只需短短鍵入幾個字元就能得到想要的結果。
但是同時 有時候命令太多記不住也很頭疼,而且有的時候,如果你不知道某個命令可以做這個事情 那麼挫敗感就會很強。

英文解釋:
encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
在這裡插入圖片描述

在這裡插入圖片描述
經典的命令模式包括如下4個角色:

Command:定義命令的統一介面
ConcreteCommand:Command介面的實現者,用來執行具體的命令,某些情況下可以直接用來充當Receiver。
Receiver:命令的實際執行者
Invoker:命令的請求者,是命令模式中最重要的角色。這個角色用來對各個命令進行控制。

角色抽象的一批。

例項

電視機是請求的接收者,遙控器是請求的傳送者,遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作。抽象命令角色由一個命令介面來扮演,有三個具體的命令類實現了抽象命令介面,這三個具體命令類分別代表三種操作:開啟電視機、關閉電視機和切換頻道。顯然,電視機遙控器就是一個典型的命令模式應用例項。

程式碼

抽象命令類:

public interface AbstractCommand{
    public void execute();
}

具體的命令類:換臺

public class TVChangeCommand implements AbstractCommand{

    private Television tv;

    public TVChangeCommand(){
        tv = new Television();
    }

    public void execute(){
        tv.changeChannel();
    }

}

具體的命令類:關機

public class TVCloseCommand implements AbstractCommand{

    private Television tv;

    public TVCloseCommand(){
        tv = new Television();
    }

    public void execute(){
        tv.close();
    }

}

具體的命令類:開機

public class TVOpenCommand implements AbstractCommand{
    
        private Television tv;
    
        public TVOpenCommand(){
        tv = new Television();
    }

    public void execute(){
        tv.open();
    }

}

接收者類

public class Television{
    
        public void open(){
        System.out.println("開啟電視機!");
    }
    
    public void close()
    {
        System.out.println("關閉電視機!");        
    }
    
    public void changeChannel()
    {
        System.out.println("切換電視訊道!");
    }

}

呼叫者(Invoker)類

public class Controller {
    private AbstractCommand openCommand, closeCommand, changeCommand;

    public Controller(AbstractCommand openCommand, AbstractCommand closeCommand, AbstractCommand changeCommand) {
        this.openCommand = openCommand;
        this.closeCommand = closeCommand;
        this.changeCommand = changeCommand;
    }

    public void open() {
        openCommand.execute();
    }

    public void change() {
        changeCommand.execute();
    }

    public void close() {
        closeCommand.execute();
    }
}

優缺點

優點

每個命令都被封裝起來,對於客戶端來說,需要什麼功能就去呼叫相應的命令,而無需知道命令具體是怎麼執行的。比如有一組檔案操作的命令:新建檔案、複製檔案、刪除檔案。如果把這三個操作都封裝成一個命令類,客戶端只需要知道有這三個命令類即可,至於命令類中封裝好的邏輯,客戶端則無需知道。

其次,命令模式的擴充套件性很好,在命令模式中,在接收者類中一般會對操作進行最基本的封裝,命令類則通過對這些基本的操作進行二次封裝,當增加新命令的時候,對命令類的編寫一般不是從零開始的,有大量的接收者類可供呼叫,也有大量的命令類可供呼叫,程式碼的複用性很好。比如,檔案的操作中,我們需要增加一個剪下檔案的命令,則只需要把複製檔案和刪除檔案這兩個命令組合一下就行了,非常方便。

缺點

命令模式的缺點就是命令如果很多,開發起來就要頭疼了。特別是很多簡單的命令,實現起來就幾行程式碼的事,而使用命令模式的話,不用管命令多簡單,都需要寫一個命令類來封裝。

例項中的例項

TomCat中的命令模式
Tomcat中Connector 也是通過命令模式呼叫 Container。Connector 作為抽象請求者,HttpConnector 作為具體請求者。HttpProcessor 作為命令。Container 作為命令的抽象接受者,ContainerBase 作為具體的接受者。客戶端就是應用伺服器 Server 元件了。Server 首先建立命令請求者 HttpConnector 物件,然後建立命令 HttpProcessor 命令物件。再把命令物件交給命令接受者 ContainerBase 容器來處理命令。命令的最終是被 Tomcat 的 Container 執行的。命令可以以佇列的方式進來,Container 也可以以不同的方式來處理請求,如 HTTP1.0 協議和 HTTP1.1 的處理方式就會不同。

相關文章