.NET中的設計模式四:命令模式

來源:互聯網
上載者:User
 命令模式(Command)結構並不複雜,簡單的說,就是將某些職責封裝成對象,對象的激發者(Invoker)和接收者(Reciever)都不過問命令的執行過程。用這樣的方式解除了激發者和接受者之間的耦合,為程式提供了更清晰的階層。實際運用中經常是將系統中的命令抽象成一個介面,所有的命令都是這個介面的實現,如下所示:

Command類是ICommand的實現,Command類實現了execute方法,其他命令類都是Command方法的子類。這樣激發者接受者和接受者面臨的環境就非常簡單了:統一作為Command類型就可以處理了。

最簡單的命令模式的實現代碼如下:

///定義Command介面

public interface ICommand

{

    void execute();

}

 

///實現ICommand介面

///Command類是所有命令的基類,在這裡實現一些命令的共同處理過程

public abstract class Command : ICommand

{

    public virtual void execute()

    {

    }

    //實現其他的方法....

}

 

///實現一個具體的Command1

public class Command1 : Command

{

    public void override execute()

    {

        //具體的處理過程

    }

}

 

///實現一個具體的Command2

public class Command2 : Command

{

    public void override execute()

    {

        //具體的處理過程

    }

}

 

///實現一個具體的Command3

public class Command3 : Command

{

    public void override execute()

    {

        //具體的處理過程

    }

}

命令模式的實際應用

下面從一個系統執行個體看一看命令模式的應用。ReportingService是一個報表系統的一部分,是一個運行在Windows系統上的Service程式,所需要完成的功能是:每天晚上11點到淩晨2點,將資料庫中的大批量的資料產生數百張報表。報表的分布較為複雜,有的要求在Web伺服器上發布報表,有的要求將報表資料輸出成一個文字檔,還有的要將報表儲存在資料庫系統中。

系統的設計運用了命令模式,其中的一部分結構如下:

程式中定義了ICommand介面,實現了多個Command類(這裡只畫出3個表示樣本),分別執行各個報表的產生任務。Command類提供了下列介面:

分類 名稱 類型 說明
屬性 finished bool 表示任務是否已經進行完畢
屬性 context IApplicationContext 任務執行需要的環境和資源,包括資料庫連接、檔案系統等等
方法 execute void 執行任務

Service的主線程每天定時將系統運行環境進行初始化,建立一個ApplicationContext類的執行個體(Application是一個Singlton模式的類,圖中沒有體現),這個類中儲存了Command運行需要使用的全部資源。然後初始化一個Command對象列表,逐個執行每一個Command。這樣一來,複雜的商務邏輯就從程式的主架構中分離開了,Service的主線程所需要做的全部工作就是協調資源的分配和異常的處理,還可以不斷檢查命令執行的狀態,看看finished屬性是否為真。如果執行完以後發現某些命令執行不成功,要做相應的處理。

程式採用了單元測試的開發方式,在對程式主線程進行測試的時候,使用了一個虛擬Command實現。測試每一個Command類的時候則為每個Command實現了虛擬ApplicationContext。這樣的結構為單元測試提供了很多便利。關於提高程式的可測試性可以參見我的另一篇文章:怎樣測試代碼中難測試的部分。

命令模式和其他模式的結合

為了給Command的建立提供一個整潔簡單的方式,Command模式經常和原廠模式(Factory)結合使用,採用一個工廠對Command對象的建立進行管理,減少命令激發者與命令對象之間的耦合程度。

在表單程式中,Command模式還經常與組合模式(Composition)結合使用。可以在初始化表單的時候,將畫面上的功能表項目、工具列、按鈕等控制項與相應的Command進行組合,這樣在控制項點擊時,調用對應的Command,即可實現對命令的處理。

在《程式員》雜誌本年第10月期介紹了一個利用Command模式實現程式中Undo功能的文章。程式中為每個Command定義了“執行”和“撤銷”兩種操作,如下:

圖中的Action就是Commamnd對象,只是名稱不同,意義是一樣的。Action對象存在do和undo方法,分別是“執行”和“撤銷”方法。可以將執行完畢的Action對象的done屬性設定為true,再將其儲存在一個列表中——ActionList。在ActionList中找到最後一個done屬性為true的Action,執行其undo方法,即可實現“撤銷”的操作。

命令類的序列化

如果將Command基類及其每一個子類都進行序列化,可以實現更多的強大的功能。程式執行過程中,如果發生異常,比如網路發生中斷、檔案丟失等異常,可以將沒有執行完畢的Command序列化儲存下來。等待可以執行的時候再將這些對象重新載入,命令可以繼續執行。甚至使用者已經重新啟動了電腦,命令也可以繼續執行。Command對象的序列化也為分布式的操作提供了便利。在網路環境中,可以在某處建立一個Command對象,將其序列化後傳輸到網路上另一台電腦上進行執行。這種情況下不要忘記異常類的序列化,如果自己定義了Exception的子類,也要將其進行序列化,以便在網路環境中捕捉和處理Command執行時發生的異常。Microsoft網站上有一篇文章介紹.NET中對象的序列化,詳細的介紹了對象序列化的概念。

參考文獻

《實用J2EE設計模式編程指南》 (美)Graig A.Berry John Carnell Matjaz B.Juric 邱仲潘

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.