15.設計模式_命令模式

1、前言

  以前一直在忙於工做上的事情,關於設計模式系列一直沒更新,最近項目中發現,對於設計模式的瞭解是必不可少的,固然對於設計模式的應用那更是重要,能夠說是否懂得應用設計模式在項目中是衡量一個程序員的技術水平,由於對於一個功能的實現,高級工程師和初級工程師同樣都會實現,可是區別在於它們實現功能的可擴展和可維護性,也就是代碼的是否「優美」、可讀。可是,要更好地應用,首先就必須瞭解各類設計模式和其應用場景,因此我仍是但願繼續完成設計模式這個系列,但願經過這種總結的方式來加深本身設計模式的理解。程序員

2、命令模式的介紹

 2.1 命令模式的定義

命令模式屬於對象的行爲型模式。命令模式是把一個操做或者行爲抽象爲一個對象中,經過對命令的抽象化來使得發出命令的責任和執行命令的責任分隔開。命令模式的實現能夠提供命令的撤銷和恢復功能。設計模式

2.2 命令模式的結構

  既然,命令模式是實現把發出命令的責任和執行命令的責任分割開,然而中間必須有某個對象來幫助發出命令者來傳達命令,使得執行命令的接收者能夠收到命令並執行命令。例如,開學了,院領導說計算機學院要進行軍訓,計算機學院的學生要跑1000米,院領導的話也就至關於一個命令,他不可能直接傳達給到學生,他必須讓教官來發出命令,並監督學生執行該命令。在這個場景中,發出命令的責任是屬於學院領導,院領導充當與命令發出者的角色,執行命令的責任是屬於學生,學生充當於命令接收者的角色,而教官就充當於命令的發出者或命令請求者的角色,然而命令模式的精髓就在於把每一個命令抽象爲對象。從而命令模式的結構以下圖所示:網絡

從命令模式的結構圖能夠看出,它涉及到五個角色,它們分別是:app

  • 客戶角色:發出一個具體的命令並肯定其接受者。
  • 命令角色:聲明瞭一個給全部具體命令類實現的抽象接口
  • 具體命令角色:定義了一個接受者和行爲的弱耦合,負責調用接受者的相應方法。
  • 請求者角色:負責調用命令對象執行命令。
  • 接受者角色:負責具體行爲的執行。

2.3 命令模式的實現

  如今,讓咱們以上面的軍訓的例子來實現一個命令模式,在實現以前,能夠參考下命令模式的結構圖來分析下實現過程。ide

  軍訓場景中,具體的命令便是學生跑1000米,這裏學生是命令的接收者,教官是命令的請求者,院領導是命令的發出者,即客戶端角色。要實現命令模式,則必須須要一個抽象命令角色來聲明約定,這裏以抽象類來來表示。命令的傳達流程是:this

  命令的發出者必須知道具體的命令、接受者和傳達命令的請求者,對應於程序也就是在客戶端角色中須要實例化三個角色的實例對象了。spa

  命令的請求者負責調用命令對象的方法來保證命令的執行,對應於程序也就是請求者對象須要有命令對象的成員,並在請求者對象的方法內執行命令。設計

  具體命令就是跑1000米,這天然屬於學生的責任,因此是具體命令角色的成員方法,而抽象命令類定義這個命令的抽象接口。日誌

  有了上面的分析以後,具體命令模式的實現代碼以下所示:code

複製代碼
 1  
 2     // 教官,負責調用命令對象執行請求
 3     public class Invoke
 4     {
 5         public Command _command;
 6 
 7         public Invoke(Command command)
 8         {
 9             this._command = command;
10         }
11 
12         public void ExecuteCommand()
13         {
14             _command.Action();
15         }
16     }
17 
18     // 命令抽象類
19     public abstract class Command 
20     {
21         // 命令應該知道接收者是誰,因此有Receiver這個成員變量
22         protected Receiver _receiver;
23 
24         public Command(Receiver receiver)
25         {
26             this._receiver = receiver;
27         }
28 
29         // 命令執行方法
30         public abstract void Action();
31     }
32 
33     // 
34     public class ConcreteCommand :Command
35     {
36         public ConcreteCommand(Receiver receiver)
37             : base(receiver)
38         { 
39         }
40 
41         public override void Action()
42         {
43             // 調用接收的方法,由於執行命令的是學生
44             _receiver.Run1000Meters();
45         }
46     }
47 
48     // 命令接收者——學生
49     public class Receiver
50     {
51         public void Run1000Meters()
52         {
53             Console.WriteLine("跑1000米");
54         }
55     }
56 
57     // 院領導
58     class Program
59     {
60         static void Main(string[] args)
61         {
62             // 初始化Receiver、Invoke和Command
63             Receiver r = new Receiver();
64             Command c = new ConcreteCommand(r);
65             Invoke i = new Invoke(c);
66             
67             // 院領導發出命令
68             i.ExecuteCommand();
69         }
70     }
複製代碼

3、.NET中命令模式的應用(引用TerryLee)

 在ASP.NET的MVC模式中,有一種叫Front Controller的模式,它分爲Handler和Command樹兩個部分,Handler處理全部公共的邏輯,接收HTTP Post或Get請求以及相關的參數並根據輸入的參數選擇正確的命令對象,而後將控制權傳遞到Command對象,由其完成後面的操做,這裏面其實就是用到了Command模式。

 

     Front Controller 的處理程序部分結構圖

 

    Front Controller的命令部分結構圖

Handler 類負責處理各個 Web 請求,並將肯定正確的 Command 對象這一職責委派給 CommandFactory 類。當 CommandFactory 返回 Command 對象後,Handler 將調用 Command 上的 Execute 方法來執行請求。具體的實現以下

 View Code

4、命令模式的適用場景

   在下面的狀況下能夠考慮使用命令模式:

  1. 系統須要支持命令的撤銷(undo)。命令對象能夠把狀態存儲起來,等到客戶端須要撤銷命令所產生的效果時,能夠調用undo方法吧命令所產生的效果撤銷掉。命令對象還能夠提供redo方法,以供客戶端在須要時,再從新實現命令效果。
  2. 系統須要在不一樣的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者能夠有不一樣的生命週期。意思爲:原來請求的發出者可能已經不存在了,而命令對象自己可能還是活動的。這時命令的接受者能夠在本地,也能夠在網絡的另外一個地址。命令對象能夠串行地傳送到接受者上去。
  3. 若是一個系統要將系統中全部的數據消息更新到日誌裏,以便在系統崩潰時,能夠根據日誌裏讀回全部數據的更新命令,從新調用方法來一條一條地執行這些命令,從而恢復系統在崩潰前所作的數據更新。
  4. 系統須要使用命令模式做爲「CallBack(回調)」在面向對象系統中的替代。Callback便是先將一個方法註冊上,而後再之後調用該方法。

5、命令模式的優缺點

   命令模式使得命令發出的一個和接收的一方實現低耦合,從而有如下的優勢:

  • 命令模式使得新的命令很容易被加入到系統裏。
  • 能夠設計一個命令隊列來實現對請求的Undo和Redo操做。
  • 能夠較容易地將命令寫入日誌。
  • 能夠把命令對象聚合在一塊兒,合成爲合成命令。合成命令式合成模式的應用。

  命令模式的缺點:

  • 使用命令模式可能會致使系統有過多的具體命令類。這會使得命令模式在這樣的系統裏變得不實際。

6、總結

   命令模式的實現要點在於把某個具體的命令抽象化爲具體的命令類,並經過加入命令請求者角色來實現將命令發送者對命令執行者的依賴分割開,在上面軍訓的例子中,若是不使用命令模式的話,則命令的發送者將對命令接收者是強耦合的關係,實現代碼以下:

複製代碼
 1  // 院領導
 2     class Program
 3     {
 4         static void Main(string[] args)
 5         {
 6            // 行爲的請求者和行爲的實現者之間呈現一種緊耦合關係
 7             Receiver r = new Receiver();
 8 
 9             r.Run1000Meters();
10         }
11     }
12 
13     public class Receiver
14     {
15         // 操做
16         public void Run1000Meters()
17         {
18             Console.WriteLine("跑1000米");
19         }
20     }
複製代碼

  到這裏,本章的內容就介紹結束了,在下一章將繼續爲你們分享下我對迭代器模式的理解。

相關文章
相關標籤/搜索