一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C#設(shè)計(jì)模式(4)——抽象工廠模式

 賈朋亮博客 2014-11-11

一、前言

  之前一直在忙于工作上的事情,關(guān)于設(shè)計(jì)模式系列一直沒(méi)更新,最近項(xiàng)目中發(fā)現(xiàn),對(duì)于設(shè)計(jì)模式的了解是必不可少的,當(dāng)然對(duì)于設(shè)計(jì)模式的應(yīng)用那更是重要,可以說(shuō)是否懂得應(yīng)用設(shè)計(jì)模式在項(xiàng)目中是衡量一個(gè)程序員的技術(shù)水平,因?yàn)閷?duì)于一個(gè)功能的實(shí)現(xiàn),高級(jí)工程師和初級(jí)工程師一樣都會(huì)實(shí)現(xiàn),但是區(qū)別在于它們實(shí)現(xiàn)功能的可擴(kuò)展和可維護(hù)性,也就是代碼的是否“優(yōu)美”、可讀。但是,要更好地應(yīng)用,首先就必須了解各種設(shè)計(jì)模式和其應(yīng)用場(chǎng)景,所以我還是希望繼續(xù)完成設(shè)計(jì)模式這個(gè)系列,希望通過(guò)這種總結(jié)的方式來(lái)加深自己設(shè)計(jì)模式的理解。

二、命令模式的介紹

2.1 命令模式的定義

命令模式屬于對(duì)象的行為型模式。命令模式是把一個(gè)操作或者行為抽象為一個(gè)對(duì)象中,通過(guò)對(duì)命令的抽象化來(lái)使得發(fā)出命令的責(zé)任和執(zhí)行命令的責(zé)任分隔開(kāi)。命令模式的實(shí)現(xiàn)可以提供命令的撤銷和恢復(fù)功能。

2.2 命令模式的結(jié)構(gòu)

  既然,命令模式是實(shí)現(xiàn)把發(fā)出命令的責(zé)任和執(zhí)行命令的責(zé)任分割開(kāi),然而中間必須有某個(gè)對(duì)象來(lái)幫助發(fā)出命令者來(lái)傳達(dá)命令,使得執(zhí)行命令的接收者可以收到命令并執(zhí)行命令。例如,開(kāi)學(xué)了,院領(lǐng)導(dǎo)說(shuō)計(jì)算機(jī)學(xué)院要進(jìn)行軍訓(xùn),計(jì)算機(jī)學(xué)院的學(xué)生要跑1000米,院領(lǐng)導(dǎo)的話也就相當(dāng)于一個(gè)命令,他不可能直接傳達(dá)給到學(xué)生,他必須讓教官來(lái)發(fā)出命令,并監(jiān)督學(xué)生執(zhí)行該命令。在這個(gè)場(chǎng)景中,發(fā)出命令的責(zé)任是屬于學(xué)院領(lǐng)導(dǎo),院領(lǐng)導(dǎo)充當(dāng)與命令發(fā)出者的角色,執(zhí)行命令的責(zé)任是屬于學(xué)生,學(xué)生充當(dāng)于命令接收者的角色,而教官就充當(dāng)于命令的發(fā)出者或命令請(qǐng)求者的角色,然而命令模式的精髓就在于把每個(gè)命令抽象為對(duì)象。從而命令模式的結(jié)構(gòu)如下圖所示:

從命令模式的結(jié)構(gòu)圖可以看出,它涉及到五個(gè)角色,它們分別是:

  • 客戶角色:發(fā)出一個(gè)具體的命令并確定其接受者。
  • 命令角色:聲明了一個(gè)給所有具體命令類實(shí)現(xiàn)的抽象接口
  • 具體命令角色:定義了一個(gè)接受者和行為的弱耦合,負(fù)責(zé)調(diào)用接受者的相應(yīng)方法。
  • 請(qǐng)求者角色:負(fù)責(zé)調(diào)用命令對(duì)象執(zhí)行命令。
  • 接受者角色:負(fù)責(zé)具體行為的執(zhí)行。

2.3 命令模式的實(shí)現(xiàn)

  現(xiàn)在,讓我們以上面的軍訓(xùn)的例子來(lái)實(shí)現(xiàn)一個(gè)命令模式,在實(shí)現(xiàn)之前,可以參考下命令模式的結(jié)構(gòu)圖來(lái)分析下實(shí)現(xiàn)過(guò)程。

  軍訓(xùn)場(chǎng)景中,具體的命令即是學(xué)生跑1000米,這里學(xué)生是命令的接收者,教官是命令的請(qǐng)求者,院領(lǐng)導(dǎo)是命令的發(fā)出者,即客戶端角色。要實(shí)現(xiàn)命令模式,則必須需要一個(gè)抽象命令角色來(lái)聲明約定,這里以抽象類來(lái)來(lái)表示。命令的傳達(dá)流程是:

  命令的發(fā)出者必須知道具體的命令、接受者和傳達(dá)命令的請(qǐng)求者,對(duì)應(yīng)于程序也就是在客戶端角色中需要實(shí)例化三個(gè)角色的實(shí)例對(duì)象了。

  命令的請(qǐng)求者負(fù)責(zé)調(diào)用命令對(duì)象的方法來(lái)保證命令的執(zhí)行,對(duì)應(yīng)于程序也就是請(qǐng)求者對(duì)象需要有命令對(duì)象的成員,并在請(qǐng)求者對(duì)象的方法內(nèi)執(zhí)行命令。

  具體命令就是跑1000米,這自然屬于學(xué)生的責(zé)任,所以是具體命令角色的成員方法,而抽象命令類定義這個(gè)命令的抽象接口。

  有了上面的分析之后,具體命令模式的實(shí)現(xiàn)代碼如下所示:

復(fù)制代碼
 1  
 2     // 教官,負(fù)責(zé)調(diào)用命令對(duì)象執(zhí)行請(qǐng)求
 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         // 命令應(yīng)該知道接收者是誰(shuí),所以有Receiver這個(gè)成員變量
22         protected Receiver _receiver;
23 
24         public Command(Receiver receiver)
25         {
26             this._receiver = receiver;
27         }
28 
29         // 命令執(zhí)行方法
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             // 調(diào)用接收的方法,因?yàn)閳?zhí)行命令的是學(xué)生
44             _receiver.Run1000Meters();
45         }
46     }
47 
48     // 命令接收者——學(xué)生
49     public class Receiver
50     {
51         public void Run1000Meters()
52         {
53             Console.WriteLine("跑1000米");
54         }
55     }
56 
57     // 院領(lǐng)導(dǎo)
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             // 院領(lǐng)導(dǎo)發(fā)出命令
68             i.ExecuteCommand();
69         }
70     }
復(fù)制代碼

三、.NET中命令模式的應(yīng)用(引用TerryLee)

在ASP.NET的MVC模式中,有一種叫Front Controller的模式,它分為Handler和Command樹(shù)兩個(gè)部分,Handler處理所有公共的邏輯,接收HTTP Post或Get請(qǐng)求以及相關(guān)的參數(shù)并根據(jù)輸入的參數(shù)選擇正確的命令對(duì)象,然后將控制權(quán)傳遞到Command對(duì)象,由其完成后面的操作,這里面其實(shí)就是用到了Command模式。

    Front Controller 的處理程序部分結(jié)構(gòu)圖

    Front Controller的命令部分結(jié)構(gòu)圖

Handler 類負(fù)責(zé)處理各個(gè) Web 請(qǐng)求,并將確定正確的 Command 對(duì)象這一職責(zé)委派給 CommandFactory 類。當(dāng) CommandFactory 返回 Command 對(duì)象后,Handler 將調(diào)用 Command 上的 Execute 方法來(lái)執(zhí)行請(qǐng)求。具體的實(shí)現(xiàn)如下

復(fù)制代碼
  1 // Handler類
  2 public class Handler : IHttpHandler
  3 
  4 {
  5     public void ProcessRequest(HttpContext context)
  6 
  7     {
  8 
  9         Command command = CommandFactory.Make(context.Request.Params);
 10 
 11         command.Execute(context);
 12 
 13     }
 14 
 15     public bool IsReusable
 16 
 17     {
 18         get
 19 
 20         {
 21             return true;
 22         }
 23     }
 24 }
 25 
 26 Command接口:
 27 /// <summary>
 28 /// Command
 29 /// </summary>
 30 public interface Command
 31 
 32 {
 33     void Execute(HttpContext context);
 34 }
 35 
 36 CommandFactory類:
 37 /// <summary>
 38 /// CommandFactory
 39 /// </summary>
 40 public class CommandFactory
 41 
 42 {
 43     public static Command Make(NameValueCollection parms)
 44 
 45     {
 46 
 47         string requestParm = parms["requestParm"];
 48 
 49         Command command = null;
 50 
 51         //根據(jù)輸入?yún)?shù)得到不同的Command對(duì)象
 52 
 53         switch (requestParm)
 54 
 55         {
 56             case "1":
 57 
 58                 command = new FirstPortal();
 59 
 60                 break;
 61 
 62             case "2":
 63 
 64                 command = new SecondPortal();
 65 
 66                 break;
 67 
 68             default:
 69 
 70                 command = new FirstPortal();
 71 
 72                 break;
 73         }
 74 
 75         return command;
 76 
 77     }
 78 }
 79 
 80 RedirectCommand類:
 81 public abstract class RedirectCommand : Command
 82 
 83 {
 84     //獲得Web.Config中定義的key和url鍵值對(duì),UrlMap類詳見(jiàn)下載包中的代碼
 85 
 86     private UrlMap map = UrlMap.SoleInstance;
 87 
 88     protected abstract void OnExecute(HttpContext context);
 89 
 90     public void Execute(HttpContext context)
 91 
 92     {
 93         OnExecute(context);
 94 
 95         //根據(jù)key和url鍵值對(duì)提交到具體處理的頁(yè)面
 96 
 97         string url = String.Format("{0}?{1}", map.Map[context.Request.Url.AbsolutePath], context.Request.Url.Query);
 98 
 99         context.Server.Transfer(url);
100 
101     }
102 }
103 
104 FirstPortal類:
105 public class FirstPortal : RedirectCommand
106 
107 {
108     protected override void OnExecute(HttpContext context)
109 
110     {
111         //在輸入?yún)?shù)中加入項(xiàng)portalId以便頁(yè)面處理
112 
113         context.Items["portalId"] = "1";
114 
115     }
116 }
117 
118 SecondPortal類:
119 public class SecondPortal : RedirectCommand
120 
121 {
122     protected override void OnExecute(HttpContext context)
123 
124     {
125         context.Items["portalId"] = "2";
126     }
127 }
復(fù)制代碼

四、命令模式的適用場(chǎng)景

  在下面的情況下可以考慮使用命令模式:

  1. 系統(tǒng)需要支持命令的撤銷(undo)。命令對(duì)象可以把狀態(tài)存儲(chǔ)起來(lái),等到客戶端需要撤銷命令所產(chǎn)生的效果時(shí),可以調(diào)用undo方法吧命令所產(chǎn)生的效果撤銷掉。命令對(duì)象還可以提供redo方法,以供客戶端在需要時(shí),再重新實(shí)現(xiàn)命令效果。
  2. 系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)。一個(gè)命令對(duì)象和原先的請(qǐng)求發(fā)出者可以有不同的生命周期。意思為:原來(lái)請(qǐng)求的發(fā)出者可能已經(jīng)不存在了,而命令對(duì)象本身可能仍是活動(dòng)的。這時(shí)命令的接受者可以在本地,也可以在網(wǎng)絡(luò)的另一個(gè)地址。命令對(duì)象可以串行地傳送到接受者上去。
  3. 如果一個(gè)系統(tǒng)要將系統(tǒng)中所有的數(shù)據(jù)消息更新到日志里,以便在系統(tǒng)崩潰時(shí),可以根據(jù)日志里讀回所有數(shù)據(jù)的更新命令,重新調(diào)用方法來(lái)一條一條地執(zhí)行這些命令,從而恢復(fù)系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。
  4. 系統(tǒng)需要使用命令模式作為“CallBack(回調(diào))”在面向?qū)ο笙到y(tǒng)中的替代。Callback即是先將一個(gè)方法注冊(cè)上,然后再以后調(diào)用該方法。

五、命令模式的優(yōu)缺點(diǎn)

  命令模式使得命令發(fā)出的一個(gè)和接收的一方實(shí)現(xiàn)低耦合,從而有以下的優(yōu)點(diǎn):

  • 命令模式使得新的命令很容易被加入到系統(tǒng)里。
  • 可以設(shè)計(jì)一個(gè)命令隊(duì)列來(lái)實(shí)現(xiàn)對(duì)請(qǐng)求的Undo和Redo操作。
  • 可以較容易地將命令寫入日志。
  • 可以把命令對(duì)象聚合在一起,合成為合成命令。合成命令式合成模式的應(yīng)用。

  命令模式的缺點(diǎn):

  • 使用命令模式可能會(huì)導(dǎo)致系統(tǒng)有過(guò)多的具體命令類。這會(huì)使得命令模式在這樣的系統(tǒng)里變得不實(shí)際。

六、總結(jié)

  命令模式的實(shí)現(xiàn)要點(diǎn)在于把某個(gè)具體的命令抽象化為具體的命令類,并通過(guò)加入命令請(qǐng)求者角色來(lái)實(shí)現(xiàn)將命令發(fā)送者對(duì)命令執(zhí)行者的依賴分割開(kāi),在上面軍訓(xùn)的例子中,如果不使用命令模式的話,則命令的發(fā)送者將對(duì)命令接收者是強(qiáng)耦合的關(guān)系,實(shí)現(xiàn)代碼如下:

復(fù)制代碼
 1  // 院領(lǐng)導(dǎo)
 2     class Program
 3     {
 4         static void Main(string[] args)
 5         {
 6            // 行為的請(qǐng)求者和行為的實(shí)現(xiàn)者之間呈現(xiàn)一種緊耦合關(guān)系
 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     }
復(fù)制代碼

  到這里,本章的內(nèi)容就介紹結(jié)束了,在下一章將繼續(xù)為大家分享下我對(duì)迭代器模式的理解。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日本加勒比在线播放一区| 亚洲天堂一区在线播放| 五月激情综合在线视频| 蜜桃传媒视频麻豆第一区| 日本不卡在线视频你懂的 | 精品老司机视频在线观看| 欧美国产亚洲一区二区三区| 成人午夜激情在线免费观看| 在线一区二区免费的视频| 免费观看潮喷到高潮大叫| 国产毛片不卡视频在线| 日韩午夜老司机免费视频| 欧美性猛交内射老熟妇| 日韩精品亚洲精品国产精品| 亚洲丁香婷婷久久一区| 国产91色综合久久高清| 欧美午夜伦理在线观看| 操白丝女孩在线观看免费高清| 少妇人妻一级片一区二区三区 | 99国产一区在线播放| 国产高清精品福利私拍| 精品国模一区二区三区欧美| 日系韩系还是欧美久久| 欧美日韩亚洲精品在线观看| 国产丝袜极品黑色高跟鞋| 亚洲超碰成人天堂涩涩| 久久精品蜜桃一区二区av| 亚洲一二三四区免费视频| 国产精品流白浆无遮挡| 欧美日韩最近中国黄片| 国产超薄黑色肉色丝袜| 亚洲中文字幕在线观看四区| 亚洲天堂久久精品成人| 日本美国三级黄色aa| 91精品国自产拍老熟女露脸 | 欧美精品二区中文乱码字幕高清| 国产毛片av一区二区三区小说| 精品视频一区二区不卡| 中文字幕五月婷婷免费| 久草精品视频精品视频精品| 国产又粗又猛又黄又爽视频免费|