一、 命令(Command)模式
命令(Command)模式屬于對象的行為模式【GOF95】。命令模式又稱為行動(Action)模式或交易(Transaction)模式。命令模式把一個請求或者操作封裝到一個對象中。命令模式允許系統使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和恢復功能。 命令模式是對命令的封裝。命令模式把發出命令的責任和執行命令的責任分割開,委派給不同的對象。 每一個命令都是一個操作:請求的一方發出請求要求執行一個操作;接收的一方收到請求,并執行操作。命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否被執行、何時被執行,以及是怎么被執行的。
宏命令也是一個具體的命令,只不過他調用了一個或多個其它命令,因此執行一個命令時就相當于執行多個命令.
二、 命令模式的結構 命令模式的類圖如下:

命令模式涉及到五個角色,它們分別是:
- 命令(Command)角色:聲明了一個給所有具體命令類的抽象接口。這是一個抽象角色。
- 具體命令(ConcreteCommand)角色:定義一個接受者和行為之間的弱耦合;實現 Execute()方法,負責調用接收考的相應操作。Execute()方法通常叫做執方法。
- 請求者(Invoker)角色:負責調用命令對象執行請求,相關的方法叫做行動方法。
- 接收者(Receiver)角色:負責具體實施和執行一個請求。任何一個類都可以成為接收者,實施和執行請求的方法叫做行動方法。
三、 玉帝傳美猴王上天
命令模式不是新的發明,在美猴王大鬧天宮之前就有了。那時玉帝命令太白金星召美猴王上天:"金星徑入(水簾洞)當中,面南立定道:'我是西方太白金星,奉玉帝招安圣旨,下界請你上大,拜受仙錄。'"玉帝是系統的客戶端,太白金星是命令的發出者,猴王是命令的接收者,圣旨就是命令。玉帝的這一道命令就是要求猴王到上界報到。玉帝只管發出命令,而不管命令是怎樣傳達到美猴王的。太白金星負責將圣旨傳到,可是美猴王怎么執行圣旨、何時執行圣旨是美猴王自己的事。果不然,不久美猴王就大鬧了天宮。 這個模擬系統的設計如下:

四、 命令模式的實現
首先命令應當"重"一些還是"輕"一些。在不同的情況下,可以做不同的選擇。如果把命令設計得"輕",那么它只是提供了一個請求者和接收者之間的耦合而己,命令代表請求者實現請求。相反,如果把命令設計的"重",那么它就應當實現所有的細節,包括請求所代表的操作,而不再需要接收者了。當一個系統沒有接收者時,就可以采用這種做法。 更常見的是處于最"輕"和最"重"的兩個極端之間時情況。命令類動態地決定調用哪一個接收者類。
其次是否支持undo和 redo。如果一個命令類提供一個方法,比如叫 unExecute(),以恢復其操作的效果,那么命令類就可以支持undo 和 redo。具體命令類需要存儲狀態信息,包括:
1. 接收者對象實際上實施請求所代表的操作;
2. 對接收者對象所作的操作所需要的參數;
3. 接收者類的最初的狀態。接收者必須提供適當的方法,使命令類可以通過調用這個方法,以便接收者類恢復原有狀態。
如果只需要提供一層的 undo和 redo,那么系統只需要存儲最后被執行的那個命令對象。如果需要支持多層的 undo 和redo,那么系統就需要存儲曾經被執行過的命令的清單,清單能允許的最大的長度便是系統所支持的undo 和 redo的層數。沿著清單逆著執行清單上的命令的反命令(unExecute())便是 undo;沿著清單順著執行清單上的命令便是 redo。
五、 在什么情況下應當使用命令模式
在下面的情況下應當考慮使用命令模式:
- 1、使用命令模式作為"CallBack"在面向對象系統中的替代。"CallBack"講的便是先將一個函數登記上,然后在以后調用此函數。
- 2、需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者可以有不同的生命期。換言之,原先的請求發出者可能已經不在了,而命令對象本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網絡的另外一個地址。命令對象可以在串行化之后傳送到另外一臺機器上去。
- 3、系統需要支持命令的撤消(undo)。命令對象可以把狀態存儲起來,等到客戶端需要撤銷命令所產生的效果時,可以調用 undo()方法,把命令所產生的效果撤銷掉。命令對象還可以提供 redo()方法,以供客戶端在需要時,再重新實施命令效果。
- 4、如果一個系統要將系統中所有的數據更新到日志里,以便在系統崩潰時,可以根據日志里讀回所有的數據更新命令,重新調用 Execute()方法一條一條執行這些命令,從而恢復系統在崩潰前所做的數據更新。
- 5、一個系統需要支持交易(Transaction)。一個交易結構封裝了一組數據更新命令。使用命令模式來實現交易結構可以使系統增加新的交易類型。
六、 使用命令模式的優點和缺點
命令允許請求的一方和接收請求的一方能夠獨立演化,從而有以下的優點:
- 命令模式使新的命令很容易地被加入到系統里。
- 允許接收請求的一方決定是否要否決(Veto)請求。
- 能較容易地設計-個命令隊列。
- 可以容易地實現對請求的 Undo和 Redo。
- 在需要的情況下,可以較容易地將命令記入日志。
- 命令模式把請求一個操作的對象與知道怎么執行一個操作的對象分割開。
- 命令類與其他任何別的類一樣,可以修改和推廣。
- 你可以把命令對象聚合在一起,合成為合成命令。比如宏命令便是合成命令的例子。合成命令是合成模式的應用。
- 由于加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易。
命令模式的缺點如下:
使用命令模式會導致某些系統有過多的具體命令類。某些系統可能需要幾十個,幾百個甚至幾千個具體命令類,這會使命令模式在這樣的系統里變得不實際