一、 命令(command)模式
命令(command)模式屬於物件的行為模式【gof95】。命令模式又稱為行動(action)模式或交易(transaction)模式。命令模式把乙個請求或者操作封裝到乙個物件中。命令模式允許系統使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。
命令模式是對命令的封裝。命令模式把發出命令的責任和執行命令的責任分割開,委派給不同的物件。
每乙個命令都是乙個操作:請求的一方發出請求要求執行乙個操作;接收的一方收到請求,並執行操作。命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的介面,更不必知道請求是怎麼被接收,以及操作是否被執行、何時被執行,以及是怎麼被執行的。
二、 命令模式的結構
既然,命令模式是實現把發出命令的責任和執行命令的責任分割開,然而中間必須有某個物件來幫助發出命令者來傳達命令,使得執行命令的接收者可以收到命令並執行命令。例如,開學了,院領導說計算機學院要進行軍訓,計算機學院的學生要跑1000公尺,院領導的話也就相當於乙個命令,他不可能直接傳達給到學生,他必須讓教官來發出命令,並監督學生執行該命令。在這個場景中,發出命令的責任是屬於學院領導,院領導充當與命令發出者的角色,執行命令的責任是屬於學生,學生充當於命令接收者的角色,而教官就充當於命令的發出者或命令請求者的角色,然而命令模式的精髓就在於把每個命令抽象為物件。從而命令模式的結構如下圖所示:
從命令模式的結構圖可以看出,它涉及到五個角色,它們分別是:
三、 命令模式的示意性源**
//四、 命令模式的實現首先命令應當"重"一些還是"輕"一些。在不同的情況下,可以做不同的選擇。如果把命令設計得"輕",那麼它只是提供了乙個請求者和接收者之間的耦合而己,命令代表請求者實現請求。command pattern -- structural example
using
system;
//"command"
abstract
class
command
//methods
abstract
public
void
execute();}//
"concretecommand"
class
concretecommand : command
//methods
public
override
void
execute()
}//"receiver"
class
receiver}//
"invoker"
class
invoker
public
void
executecommand()
}///
///client test
///
public
class
client
}
相反,如果把命令設計的"重",那麼它就應當實現所有的細節,包括請求所代表的操作,而不再需要接收者了。當乙個系統沒有接收者時,就可以採用這種做法。
更常見的是處於最"輕"和最"重"的兩個極端之間時情況。命令類動態地決定呼叫哪乙個接收者類。
其次是否支援undo和redo。如果乙個命令類提供乙個方法,比如叫unexecute(),以恢復其操作的效果,那麼命令類就可以支援undo和redo。具體命令類需要儲存狀態資訊,包括:
接收者物件實際上實施請求所代表的操作;
對接收者物件所作的操作所需要的引數;
接收者類的最初的狀態。接收者必須提供適當的方法,使命令類可以通過呼叫這個方法,以便接收者類恢復原有狀態。
如果只需要提供一層的undo和redo,那麼系統只需要儲存最後被執行的那個命令物件。如果需要支援多層的undo和redo,那麼系統就需要儲存曾經被執行過的命令的清單,清單能允許的最大的長度便是系統所支援的undo和redo的層數。沿著清單逆著執行清單上的命令的反命令(unexecute())便是undo;沿著清單順著執行清單上的命令便是redo。
五、 命令模式的實際應用案例
//六、 命令模式的適用場景在下面的情況下可以考慮使用命令模式:command pattern -- real world example
using
system;
using
system.collections;
//"command"
abstract
class
command
//"concretecommand"
class
calculatorcommand : command
//properties
public
char
operator
}public
intoperand
}//methods
override
public
void
execute()
override
public
void
unexecute()
//private helper function
private
char undo(char
@operator)
return
undo;
}}//
"receiver"
class
calculator
console.writeline(
"total = (following )",
_total, @operator, operand);
}}//
"invoker"
class
user
levels
", levels);
//perform redo operations
for (int i = 0; i < levels; i++)
if (_current < _commands.count - 1
) ((command)_commands[_current++]).execute();
}public
void undo(int
levels)
levels
", levels);
//perform undo operations
for (int i = 0; i < levels; i++)
if (_current > 0
) ((command)_commands[--_current]).unexecute();
}public
void compute(char @operator, int
operand)
}///
//////
public
class
client
}
系統需要支援命令的撤銷(undo)。命令物件可以把狀態儲存起來,等到客戶端需要撤銷命令所產生的效果時,可以呼叫undo方法吧命令所產生的效果撤銷掉。命令物件還可以提供redo方法,以供客戶端在需要時,再重新實現命令效果。
系統需要在不同的時間指定請求、將請求排隊。乙個命令物件和原先的請求發出者可以有不同的生命週期。意思為:原來請求的發出者可能已經不存在了,而命令物件本身可能仍是活動的。這時命令的接受者可以在本地,也可以在網路的另乙個位址。命令物件可以序列地傳送到接受者上去。
如果乙個系統要將系統中所有的資料訊息更新到日誌裡,以便在系統崩潰時,可以根據日誌裡讀回所有資料的更新命令,重新呼叫方法來一條一條地執行這些命令,從而恢復系統在崩潰前所做的資料更新。
系統需要使用命令模式作為「callback(**)」在物件導向系統中的替代。callback即是先將乙個方法註冊上,然後再以後呼叫該方法。
乙個系統需要支援交易(transaction)。乙個交易結構封裝了一組資料更新命令。使用命令模式來實現交易結構可以使系統增加新的交易型別。
七、 命令模式的優缺點
命令模式使得命令發出的乙個和接收的一方實現低耦合,從而有以下的優點:
命令模式的缺點:
C 設計模式 命令模式
命令模式 command 將乙個請求封裝為乙個物件,從而使你可以不同的請求對客戶進行引數化 對請求排隊或記錄請求日誌,以及支援可撤銷的操作。命令模式結構圖 command類,用來宣告執行操作的介面。class command protected receiver receiver public co...
c 設計模式(命令模式)
good 一 建立命令佇列 二 可以將命令記入日誌 三 接收請求的一方可以拒絕 四 新增乙個新命令類不影響其它類 命令模式把請求乙個操作的物件與知道怎麼操行乙個操作的物件分開 例 include include include using namespace std 烤肉師傅 class barbu...
c 設計模式 命令模式
在軟體開發系統中,常常出現 方法的請求者 與 方法的實現者 之間存在緊密的耦合關係。這不利於軟體功能的擴充套件與維護。例如,想對行為進行 撤銷 重做 記錄 等處理都很不方便,因此 如何將方法的請求者與方法的實現者解耦?變得很重要,命令模式能很好地解決這個問題。在現實生活中,這樣的例子也很多,例如,電...