> 話說,《西游記》中有這樣一段故事,玉帝命令太白金星召美猴王上天:"金星徑入水簾洞當中,面南立定道:我是西方太白金星,奉玉帝招安圣旨,請你上界報道,拜受仙錄。具體對話內容如下所示:
> 太白金星:大圣,我主玉帝聽說你才能出眾,對你非常期待啊。
> 孫大圣:是么,真的?
> 太白金星:上界眾仙也很仰慕大圣你啊。
> 孫大圣:這......
> 太白金星:大圣還猶豫是么?
> 孫大圣:我去做什么?
> 太白金星:絕對一把手,你的地盤好像很大,具體上去就知道了。
> 孫大圣:那我去看看也好。
> 太白金星:哈哈,大圣,請!
今天我們的設計模式就從孫大圣上界報道開始說起---命令模式,即將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤消的操作。在軟件系統中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合,比如要對行為進行“記錄、撤銷/重做、事務”等處理,這種無法抵御變化的緊耦合是不合適的。在這種情況下,如何將“行為請求者”與“行為實現者”解耦?將一組行為抽象為對象,實現二者之間的松耦合。
命令模式屬于行為模式。意圖是將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求的排隊或記錄請求的日志,以及支持可以撤銷的操作。又叫動作(Action)或者事務(Transaction)。有時必須向一個對象提交請求,但是并不知道關于被請求的操作或者請求的接受者的任何信息。命令模式通過將請求本身變成一個對象來使工具箱對象可向未指定的應用對象提出請求,這個對象可以被存儲并像其他的對象一樣被傳遞,這一個模式的關鍵是抽象的Command類,它定義了一個執行操作的接口,其最簡單的形式是一個抽象的Execute操作,具體的Command子類將接收者作為其一個實例變量,并實現Execute操作,制定接收者采取的動作,而接收者有執行該請求所需的具體信息。這就是命令模式(Command Pattern)首先來看一下命令模式的結構圖:
? ? ? ??
來分析一下,孫悟空上界報道中的邏輯關系,'"玉帝是系統的客戶端,太白金星是命令的發出者,猴王是命令的接收者,圣旨就是命令。玉帝的這一道命令就是要求猴王到上界報到。玉帝只管發出命令,而不管命令是怎樣傳達到美猴王的。太白金星負責將圣旨傳到,可是美猴王怎么執行圣旨、何時執行圣旨是美猴王自己的事。來看一下代碼實現:
? ? ? ??
~~~
using?System;??
using?System.Collections.Generic;??
using?System.Linq;??
using?System.Text;??
using?System.Threading.Tasks;??
??
namespace?ConsoleApplication1??
{??
????class?Program??
????{??
????????static?void?Main(string[]?args)??
????????{??
????????????ImperialEdict?i?=?new?ImperialEdict();??
????????????Command?c?=?new?ReportCommand();??
????????????Venus?v?=?new?Venus();??
????????????v.ObtainOrder();??
????????????v.ExcuteCommand();??
????????????Console.Read();??
????????}??
????}??
??
????//抽象命令類??
????//抽象命令??
????public?abstract??class?Command??
????{??
????????protected?Imperial?receiver;??
????????public?Command(Imperial?receiver)??
????????{??
????????????this.receiver?=?receiver;??
????????}??
??
????????//執行命令??
????????abstract?public?void?ExcuteCommand();??
????}??
??
????//具體命令類??
????//上界報到命令??
????class?ReportCommand?:?Imperial??
????{??
????????public?ReportCommand(Imperial?receiver)??
???????????:base(receiver)??
??????????{?}??
??
??????????public?override?void?ExcuteCommand()??
???????????{??
?????????????receiver.Report();??
???????????}??
????}??
?????
??
????//太白金星??
????public?class?Venus???
????{??
????????private?Imperial?command;??
??
????????//收到命令??
????????public?void?ObtainOrder(Imperial?command)??
????????{??
????????????this.command?=command?;??
????????}??
??
????????//執行命令??
????????public?void?Notify()??
????????{??
????????????command.ExcuteCommand?();??
????????}??
????}??
??
????//猴王??
????public?class?MonkeyKing??
????{??
????????//上界報道??
????????public?void?Imperial()??
????????{??
????????????Console?.WriteLine?("上界報道!");??
????????}??
??
??????????
????}??
??
}??
~~~
對于命令模式,我們可以這樣理解,提供一個抽象的Command接口,將執行命令操作的方法封裝到Command類接口中,ConcreteCommand實現這個Command接口方法,通過調用Receiver實例變量處理請求。客戶端定義一個Invoker對象存儲該concreteCommand對象,該invoker通過調用command對象的遞交一個請求。