c#設計模式系列:命令模式(Command Pattern)

來源:互聯網
上載者:User

標籤:18C   cancel   允許   介面實現   通知   介面   意義   lock   each   

引言

  命令模式,我感覺“命令”就是任務,執行了命令就完成了一個任務。或者說,命令是任務,我們再從這個名字上並不知道命令的發出者和接受者分別是誰,為什麼呢?因為我們並不關心他們是誰,發出命令的人發出命令,可以繼續做其他的事情,接受命令的人執行任務就可以,不需要你發出命令,還要監督我們完成,只要我們完成任務是合格的就行。這種行為也就是“解耦”,命令模式用得比較少,一般都是在實際項目開發的後發現需要用的時候我們通過重構來實現。在現實生活中,我們也用這個設計模式,例如:我們去吃大排檔,到店告訴服務員來盤啤酒小龍蝦、烤魚一份,一箱啤酒,過了一會告訴服務員不要烤魚了,這裡我們不需要關心具體是哪個大廚炒菜,只需要告訴服務員我們需要什麼就可以了

命令模式介紹

命令模式的定義

   將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化,對請求排隊或記錄請求日誌,以及支援可撤銷的操作

命令模式的結構圖

命令模式的組成

  從命令模式的結構圖可以看出,它涉及到五個角色,它們分別是:
(1)、客戶角色(Client):建立具體的命令對象,並且設定命令對象的接收者。注意這個不是我們常規意義上的用戶端,而是在組裝命令對象和接收者,或許,把這個Client稱為裝配者會更好理解,因為真正使用命令的用戶端是從Invoker來觸發執行。
(2)、命令角色(Command):聲明了一個給所有具體命令類實現的抽象介面。
(3)、具體命令角色(ConcreteCommand):命令介面實現對象,是“虛”的實現;通常會持有接收者,並調用接收者的功能來完成命令要執行的操作。
(4)、要求者角色(Invoker):要求命令對象執行請求,通常會持有命令對象,可以持有很多的命令對象。這個是用戶端真正觸發命令並要求命令執行相應操作的地方,也就是說相當於使用命令對象的入口。
(5)、接受者角色(Receiver):接收者,真正執行命令的對象。任何類都可能成為一個接收者,只要它能夠實現命令要求實現的相應功能。

命令模式的代碼實現

   第一版無模式

    class Program    {        static void Main(string[] args)        {            Barbecuer boy = new Barbecuer();            boy.BakeMutton();            boy.BakeMutton();            boy.BakeMutton();            boy.BakeChickenWing();            boy.BakeMutton();            boy.BakeMutton();            boy.BakeChickenWing();            Console.Read();        }    }    //烤肉串者    public class Barbecuer    {        //烤羊肉        public void BakeMutton()        {            Console.WriteLine("烤羊肉串!");        }        //烤雞翅        public void BakeChickenWing()        {            Console.WriteLine("烤雞翅!");        }    }
View Code

這種方法可以看出命令的寄件者將對命令接收者是強耦合的關係

第二版引入命令模式

//用戶端    class Program    {        static void Main(string[] args)        {            //開店前的準備            Barbecuer boy = new Barbecuer();            Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);            Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);            Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);            Waiter girl = new Waiter();            //開門營業 顧客點菜            girl.SetOrder(bakeMuttonCommand1);            girl.SetOrder(bakeMuttonCommand2);            girl.SetOrder(bakeChickenWingCommand1);            //點菜完閉,通知廚房            girl.Notify();            Console.Read();        }//服務員    public class Waiter    {        private IList<Command> orders = new List<Command>();        //設定訂單        public void SetOrder(Command command)        {            if (command.ToString() == "命令模式.BakeChickenWingCommand")            {                Console.WriteLine("服務員:雞翅沒有了,請點別的燒烤。");            }            else            {                orders.Add(command);                Console.WriteLine("增加訂單:" + command.ToString() + "  時間:" + DateTime.Now.ToString());            }        }        //取消訂單        public void CancelOrder(Command command)        {            orders.Remove(command);            Console.WriteLine("取消訂單:" + command.ToString() + "  時間:" + DateTime.Now.ToString());        }        //通知全部執行        public void Notify()        {            foreach (Command cmd in orders)            {                cmd.ExcuteCommand();            }        }    }    //抽象命令    public abstract class Command    {        protected Barbecuer receiver;        public Command(Barbecuer receiver)        {            this.receiver = receiver;        }        //執行命令        abstract public void ExcuteCommand();    }    //烤羊肉串命令    class BakeMuttonCommand : Command    {        public BakeMuttonCommand(Barbecuer receiver)            : base(receiver)        { }        public override void ExcuteCommand()        {            receiver.BakeMutton();        }    }    //烤雞翅命令    class BakeChickenWingCommand : Command    {        public BakeChickenWingCommand(Barbecuer receiver)            : base(receiver)        { }        public override void ExcuteCommand()        {            receiver.BakeChickenWing();        }    }    //烤肉串者    public class Barbecuer    {        public void BakeMutton()        {            Console.WriteLine("烤羊肉串!");        }        public void BakeChickenWing()        {            Console.WriteLine("烤雞翅!");        }    }
View Code命令模式的實現情境

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

  1. 系統需要支援命令的撤銷(undo)。命令對象可以把狀態儲存起來,等到用戶端需要撤銷命令所產生的效果時,可以調用undo方法吧命令所產生的效果撤銷掉。命令對象還可以提供redo方法,以供用戶端在需要時,再重新實現命令效果。
  2. 系統需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者可以有不同的生命週期。意思為:原來請求的發出者可能已經不存在了,而命令對象本身可能仍是活動的。這時命令的接受者可以在本地,也可以在網路的另一個地址。命令對象可以串列地傳送到接受者上去。
  3. 如果一個系統要將系統中所有的資料訊息更新到日誌裡,以便在系統崩潰時,可以根據日誌裡讀回所有資料的更新命令,重新調用方法來一條一條地執行這些命令,從而恢複系統在崩潰前所做的資料更新。
  4. 系統需要使用命令模式作為“CallBack(回調)”在物件導向系統中的替代。Callback即是先將一個方法註冊上,然後再以後調用該方法。
命令模式優缺點

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

  • 命令模式使得新的命令很容易被加入到系統裡。
  • 可以設計一個命令隊列來實現對請求的Undo和Redo操作。
  • 可以較容易地將命令寫入日誌。
  • 可以把命令對象彙總在一起,合成為合成命令。合成命令式合成模式的應用。

命令模式的缺點:

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

命令模式能叫容易地設計一個命令隊列,第二,在需要的情況下,可以較容易地將命令記入日誌,第三,允許接受請求的一方是否否決請求。第四,可以容易地實現對請求的撤銷與重做,第五,由於加進新的具體命令類不影響其它的類,因此新增新的具體命令類很容易,第六,命令模式把請求一個操作的對象與知道怎麼執行一個操作的對象分割開


   永遠不要讓自己原地踏步--

c#設計模式系列:命令模式(Command Pattern)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.