一、 命令(Command)模式
命令(Command)模式屬于對象的行為模式【GOF95】。命令模式又稱為行動(Action)模式或交易(Transaction)模式。命令模式把一個請求或者操作封裝到一個對象中。命令模式允許系統(tǒng)使用不同的請求把客戶端參數(shù)化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和恢復功能。 命令模式是對命令的封裝。命令模式把發(fā)出命令的責任和執(zhí)行命令的責任分割開,委派給不同的對象。 每一個命令都是一個操作:請求的一方發(fā)出請求要求執(zhí)行一個操作;接收的一方收到請求,并執(zhí)行操作。命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否被執(zhí)行、何時被執(zhí)行,以及是怎么被執(zhí)行的。
宏命令也是一個具體的命令,只不過他調(diào)用了一個或多個其它命令,因此執(zhí)行一個命令時就相當于執(zhí)行多個命令.
二、 命令模式的結(jié)構(gòu) 命令模式的類圖如下:
命令模式涉及到五個角色,它們分別是:
- 命令(Command)角色:聲明了一個給所有具體命令類的抽象接口。這是一個抽象角色。
- 具體命令(ConcreteCommand)角色:定義一個接受者和行為之間的弱耦合;實現(xiàn) Execute()方法,負責調(diào)用接收考的相應操作。Execute()方法通常叫做執(zhí)方法。
- 請求者(Invoker)角色:負責調(diào)用命令對象執(zhí)行請求,相關(guān)的方法叫做行動方法。
- 接收者(Receiver)角色:負責具體實施和執(zhí)行一個請求。任何一個類都可以成為接收者,實施和執(zhí)行請求的方法叫做行動方法。
三、 玉帝傳美猴王上天
命令模式不是新的發(fā)明,在美猴王大鬧天宮之前就有了。那時玉帝命令太白金星召美猴王上天:"金星徑入(水簾洞)當中,面南立定道:'我是西方太白金星,奉玉帝招安圣旨,下界請你上大,拜受仙錄。'"玉帝是系統(tǒng)的客戶端,太白金星是命令的發(fā)出者,猴王是命令的接收者,圣旨就是命令。玉帝的這一道命令就是要求猴王到上界報到。玉帝只管發(fā)出命令,而不管命令是怎樣傳達到美猴王的。太白金星負責將圣旨傳到,可是美猴王怎么執(zhí)行圣旨、何時執(zhí)行圣旨是美猴王自己的事。果不然,不久美猴王就大鬧了天宮。 這個模擬系統(tǒng)的設計如下:
四、 命令模式的實現(xiàn)
首先命令應當"重"一些還是"輕"一些。在不同的情況下,可以做不同的選擇。如果把命令設計得"輕",那么它只是提供了一個請求者和接收者之間的耦合而己,命令代表請求者實現(xiàn)請求。相反,如果把命令設計的"重",那么它就應當實現(xiàn)所有的細節(jié),包括請求所代表的操作,而不再需要接收者了。當一個系統(tǒng)沒有接收者時,就可以采用這種做法。 更常見的是處于最"輕"和最"重"的兩個極端之間時情況。命令類動態(tài)地決定調(diào)用哪一個接收者類。
其次是否支持undo和 redo。如果一個命令類提供一個方法,比如叫 unExecute(),以恢復其操作的效果,那么命令類就可以支持undo 和 redo。具體命令類需要存儲狀態(tài)信息,包括:
1. 接收者對象實際上實施請求所代表的操作;
2. 對接收者對象所作的操作所需要的參數(shù);
3. 接收者類的最初的狀態(tài)。接收者必須提供適當?shù)姆椒?,使命令類可以通過調(diào)用這個方法,以便接收者類恢復原有狀態(tài)。
如果只需要提供一層的 undo和 redo,那么系統(tǒng)只需要存儲最后被執(zhí)行的那個命令對象。如果需要支持多層的 undo 和redo,那么系統(tǒng)就需要存儲曾經(jīng)被執(zhí)行過的命令的清單,清單能允許的最大的長度便是系統(tǒng)所支持的undo 和 redo的層數(shù)。沿著清單逆著執(zhí)行清單上的命令的反命令(unExecute())便是 undo;沿著清單順著執(zhí)行清單上的命令便是 redo。
五、 在什么情況下應當使用命令模式
在下面的情況下應當考慮使用命令模式:
- 1、使用命令模式作為"CallBack"在面向?qū)ο笙到y(tǒng)中的替代。"CallBack"講的便是先將一個函數(shù)登記上,然后在以后調(diào)用此函數(shù)。
- 2、需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發(fā)出者可以有不同的生命期。換言之,原先的請求發(fā)出者可能已經(jīng)不在了,而命令對象本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網(wǎng)絡的另外一個地址。命令對象可以在串行化之后傳送到另外一臺機器上去。
- 3、系統(tǒng)需要支持命令的撤消(undo)。命令對象可以把狀態(tài)存儲起來,等到客戶端需要撤銷命令所產(chǎn)生的效果時,可以調(diào)用 undo()方法,把命令所產(chǎn)生的效果撤銷掉。命令對象還可以提供 redo()方法,以供客戶端在需要時,再重新實施命令效果。
- 4、如果一個系統(tǒng)要將系統(tǒng)中所有的數(shù)據(jù)更新到日志里,以便在系統(tǒng)崩潰時,可以根據(jù)日志里讀回所有的數(shù)據(jù)更新命令,重新調(diào)用 Execute()方法一條一條執(zhí)行這些命令,從而恢復系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。
- 5、一個系統(tǒng)需要支持交易(Transaction)。一個交易結(jié)構(gòu)封裝了一組數(shù)據(jù)更新命令。使用命令模式來實現(xiàn)交易結(jié)構(gòu)可以使系統(tǒng)增加新的交易類型。
- 命令模式使新的命令很容易地被加入到系統(tǒng)里。
- 允許接收請求的一方?jīng)Q定是否要否決(Veto)請求。
- 能較容易地設計-個命令隊列。
- 可以容易地實現(xiàn)對請求的 Undo和 Redo。
- 在需要的情況下,可以較容易地將命令記入日志。
- 命令模式把請求一個操作的對象與知道怎么執(zhí)行一個操作的對象分割開。
- 命令類與其他任何別的類一樣,可以修改和推廣。
- 你可以把命令對象聚合在一起,合成為合成命令。比如宏命令便是合成命令的例子。合成命令是合成模式的應用。
- 由于加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易。