Posted on 2007-12-05 13:23
flustar 閱讀(1402)
評論(0) 編輯 收藏 所屬分類:
Design Patterns
一、 Command模式定義:
將一個請求封裝為一個對象,從而使你不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
二、 模式解說
Commad模式是一種對象行為模式,它可以對發送者(sender)和接收者(receiver)完全解耦(decoupling)。("發送者" 是請求操作的對象,"接收者" 是接收請求并執行某操作的對象。有了 "解耦",發送者對接收者的接口一無所知。)這里,"請求"(request)這個術語指的是要被執行的命令。Command模式還讓我們可以對 "何時" 以及 "如何" 完成請求進行改變。因此,Command模式為我們提供了靈活性和可擴展性。
三、 結構圖
Command模式結構圖如下:

四、 怎么使用?
1) 定義一個Command接口,接口中有一個統一的方法,這就是將請求/命令封裝為對象。
2) 定義具體不同命令類ConcreteCommand實現Command接口。
3) 定義一個命令的調用角色Invoker。
4) 定義一個命令執行狀態的接收者Receiver(非必須)。
五、 一個例子
class Document{
public void display(){
System.out.println("顯示文檔內容");
}
public void undo(){
System.out.println("撤銷文檔內容");
}
public void redo(){
System.out.println("重做文檔內容");
}
}
interface DocumentCommand{
public void execute();
}
class DisplayCommand implements DocumentCommand{
private Document document;
public DisplayCommand(Document doc){
document=doc;
}
public void execute() {
document.display();
}
}
class UndoCommand implements DocumentCommand{
private Document document;
public UndoCommand(Document doc){
document=doc;
}
public void execute() {
document.undo();
}
}
class RedoCommand implements DocumentCommand{
private Document document;
public RedoCommand(Document doc){
document=doc;
}
public void execute(){
document.redo();
}
}
class DocumentInvoker{
private DisplayCommand _dcmd;
private UndoCommand _ucmd;
private RedoCommand _rcmd;
public DocumentInvoker(DisplayCommand dcmd,UndoCommand ucmd,RedoCommand rcmd){
this._dcmd=dcmd;
this._ucmd=ucmd;
this._rcmd=rcmd;
}
public void display(){
_dcmd.execute();
}
public void undo(){
_ucmd.execute();
}
public void redo(){
_rcmd.execute();
}
}
public class CommandTest {
public static void main(String[] args) {
Document doc=new Document();
DisplayCommand display=new DisplayCommand(doc);
UndoCommand undo=new UndoCommand(doc);
RedoCommand redo=new RedoCommand(doc);
DocumentInvoker invoker=new DocumentInvoker(display,undo,redo);
invoker.display();
invoker.undo();
invoker.redo();
}
}
六、 適用性
1) 使用命令模式作為"CallBack"在面向對象系統中的替代。"CallBack"講的便是先將一個函數登記上,然后在以后調用此函數。
2) 需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者可以有不同的生命期。換言之,原先的請求發出者可能已經不在了,而命令對象本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網絡的另外一個地址。命令對象可以在串形化之后傳送到另外一臺機器上去。
3) 系統需要支持命令的撤消(undo)。命令對象可以把狀態存儲起來,等到客戶端需要撤銷命令所產生的效果時,可以調用undo()方法,把命令所產生的效果撤銷掉。命令對象還可以提供redo()方法,以供客戶端在需要時,再重新實施命令效果。
4) 如果一個系統要將系統中所有的數據更新到日志里,以便在系統崩潰時,可以根據日志里讀回所有的數據更新命令,重新調用Execute()方法一條一條執行這些命令,從而恢復系統在崩潰前所做的數據更新。
七、 優缺點
1) 優點: Command模式將 "調用操作的對象"(DocumentInvoker)和 "知道如何執行操作的對象" (Document)完全分離開來。這帶來了很大的靈活性:發送請求的對象只需要知道如何發送;它不必知道如何完成請求。
2) 會導致某些系統有過多的具體命令類。
八、 參考
http://www.1-100.org/JSP/13170.htm
http://terrylee.cnblogs.com/archive/2006/07/17/Command_Pattern.html
http://www.jdon.com/designpatterns/command.htm
http://www.cnblogs.com/zhenyulu/articles/69858.html