设计模式学习笔记(十七)——Command命令模式
Command命令模式介紹:
Command命令模式是一種對象行為型模式,它主要解決的問題是:在軟件構建過程中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”的問題。如下圖:
?
有時我們必須向某對象提交請求,但并不知道關于被請求的操作或請求的接受者的任何信息,此時無法抵御變化的緊耦合是不合適的。如:需要對行為進行“記錄、撤銷/重做、事務”等處理。我們所要做的是將依賴關系轉化,將緊耦合變為松耦合。則上圖的形式轉化為如下形式:
???????
?
?????? Command模式通過將請求本身變成一個對象來使行為請求者可向未指定的應用對象提出請求。
?????? GoF《設計模式》中說道:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
Command命令模式結構:
??????
?
?
定義場景:
?????? 現在來看一個場景:對于notepad大家都很熟悉,在我們使用notepad打開一個文檔之后,往往做一些操作,如;輸入字符(Write)、刪除前一個字符(Delete)、撤銷剛才的操作(UnDo)?,F在我們就用Console程序模擬這個過程。
代碼實現與結構分析:
?????? 在實現代碼前先說明實現Command模式需要烤爐的一些問題:
1、? 一個命令對象應達到何種智能程度:命令對象的能力可大可小。這樣就出現了兩個極端。一是:它僅確定一個接收者和執行該請求的動作;一是:它自己實現所有功能,根本不需要額外的接收者對象。我給他們起了便于我方便記憶的名字,第一種叫OperationCommand,第二種叫ObjectCommand。當然只是為了便于記憶和理解,如有不理解,在代碼實現與結構分析最后我會再談談我的想法,如有不妥,還請多提意見,一會在下面的代碼中會分別對這兩種情況進行示范。
2、? 支持取消和重做:為了達到這個目的ConcreteCommand類中要存儲額外的狀態信息。也就是上圖中ConcreteCommand的state屬性。
3、? 避免取消操作中過程中的錯誤積累:由于命令重復的執行、取消執行和重執行的過程可能會積累錯誤,以致一個應用的狀態最終偏離初始值。這就有必要在Command中存入更多的信息以保證這些對象可被精確的復原。
下面來看看代碼上的實現:首先,我先作一個OperationCommand的例子,先做一個請求的接收者Document(也就是結構圖中的Receiver)
class Document
??? {
??????? public string strContent;
?
??????? public Document()
??????? {
??????????? strContent = "";
??????? }
}
?
在這個程序中我們還要定義一個抽象類Command,對于OperationCommand類型來說,它僅確定一個接收者和執行該請求的動作。所以,在抽象類Command中,只聲明一個Excute的方法。這個方法在其子類中進行實現。(當然這個Command還可以定義成接口)
abstract class Command
??? {
??????? public Command()
??????? { }
??????? public abstract void Excute();
}
?
接下來,就要實現各種操作(結構圖中的ConcreteCommand),代碼如下
//寫操作
class WriteCommand :Command
??? {
??????? Document doc;
??????? ArrayList ObjectState;
??????? public WriteCommand(Document doc,ArrayList state)
??????? {
??????????? this.doc = doc;
??????????? ObjectState = state;
??????? }
?
??????? public override void Excute()
??????? {
??????????? doc.strContent += Console.ReadLine();
??????????? ObjectState.Add(doc.strContent);
??????? }
??? }
???
??? //刪除操作
??? class DeleteCommand : Command
??? {
??????? Document doc;
??????? ArrayList ObjectState;
??????? public DeleteCommand(Document doc,ArrayList state)
??????? {
??????????? this.doc = doc;
??????????? ObjectState = state;
??????? }
?
??????? public override void Excute()
??????? {
??????????? doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);
??????????? ObjectState.Add(doc.strContent);
??????? }
??? }
?
??? //撤銷操作
??? class UnDoCommand : Command
??? {
??????? Document doc;
??????? ArrayList ObjectState;
??????? public UnDoCommand(Document doc,ArrayList state)
??????? {
??????????? this.doc = doc;
??????????? ObjectState = state;
??????? }
?
??????? public override void Excute()
??????? {
??????????? doc.strContent = (string)ObjectState[ObjectState.Count - 2];
??????????? ObjectState.Add(doc.strContent);
??????? }
}
?
實現了各種操作后,編寫一個客戶代碼進行測試
class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? Document doc = new Document();
??????????? Console.WriteLine("Please Input next operation:");
??????????? string strOperation =Console.ReadLine();
??? ????????Command com = null;
??????????? ArrayList ObjectState =new ArrayList();//Record state
??????????? while (strOperation !="Exit")
??????????? {
??????????????? switch (strOperation.ToLower())
??????????????? {
??????????????????? case "write":
??? ????????????????????com = newWriteCommand(doc, ObjectState);
??????????????????????? com.Excute();
??????????????????????? Console.WriteLine("Write Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? case "del":
???????????? ???????????com = newDeleteCommand(doc, ObjectState);
??????????????????????? com.Excute();
??????????????????????? Console.WriteLine("Delete Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? case "undo":
?????????????????? ?????com = newUnDoCommand(doc, ObjectState);
??????????????????????? com.Excute();
??????????????????????? Console.WriteLine("UnDo Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? default:
??????????????????????? Console.WriteLine("Wrong Operation:");
??????????????????????? break;
??????????????? }
??????????????? Console.WriteLine("Please Input next operation:");
??????????????? strOperation = Console.ReadLine();
??????????? }
??????? }
}
?
測試結果:
Please Input next operation:
write
k
Write Operation:k
Please Input next operation:
write
i
Write Operation:ki
Please Input next operation:
write
d
Write Operation:kid
Please Input next operation:
write
d
Write Operation:kidd
Please Input next operation:
del
Delete Operation:kid
Please Input next operation:
undo
UnDo Operation:kidd
Please Input next operation:
?
下面再來實現以下ObjectCommand的例子,首先還是編寫一個已存在的請求接收者Document(結構圖中的Receiver)
class Document
??? {
??????? public string strContent;
?
??????? public Document()
??????? {
??????????? strContent = "";
??????? }
}
?
接下來實現抽象類Command(也可以使用接口),對于ObjectCommand類型來說,它自己實現所有功能,根本不需要額外的接收者對象,所以在Command中聲明了所有的操作
abstract class Command
??? {
??????? public Command()
??????? {? }
?
??????? public abstract void Write();
??????? public abstract void Delete();
??????? public abstract void UnDo();
}
?
有了Command,就可以實現具體的操作類型DocumentCommand(結構圖中的ConcreteCommand)
class DocumentCommand :Command
??? {
??????? private Document doc;
??????? private ArrayList ObjectState = new ArrayList();//Record State
??????? public DocumentCommand(Document doc)
??????? {
??????????? this.doc = doc;
??????? }
?
??????? public override void Write()
??????? {
??????????? Console.WriteLine("Please input an character:");
??????????? string strRead = Console.ReadLine();
??????????? doc.strContent += strRead;
??????????? ObjectState.Add(doc.strContent);
??????? }
?
???? ???public override void Delete()
??????? {
??????????? doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);
??????????? ObjectState.Add(doc.strContent);???????????
??????? }
?
??????? public override void UnDo()
??????? {
??????????? doc.strContent = (string)ObjectState[ObjectState.Count - 2];
??????????? ObjectState.Add(doc.strContent);
??????? }
}??
?
接下來就用一個客戶端代碼作一下測試
class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? Document doc = new Document();
???? ???????DocumentCommand com =new DocumentCommand(doc);
??????????? Console.WriteLine("Please Input next operation:");
??????????? string strOperation =Console.ReadLine();
??????????? while (strOperation !="Exit")
??????????? {
??????????????? switch (strOperation.ToLower())
??????????????? {
??????????????????? case "write":
??????????????????????? com.Write();
??????????????????????? Console.WriteLine("Write Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? case "del":
?? ?????????????????????com.Delete();
??????????????????????? Console.WriteLine("Delete Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? case "undo":
??????????????????????? com.UnDo();
??????????????????????? Console.WriteLine("UnDo Operation:" + doc.strContent);
??????????????????????? break;
??????????????????? default:
??????????????????????? Console.WriteLine("Wrong Operation:");
??????????????????????? break;
??????????????? }
??????????????? Console.WriteLine("Please Input next operation:");
??????????????? strOperation = Console.ReadLine();
??????????? }
??????? }
??? }
?
測試結果如下:
Please Input next operation:
write
Please input an character:
k
Write Operation:k
Please Input next operation:
write
Please input an character:
i
Write Operation:ki
Please Input next operation:
write
Please input an character:
d
Write Operation:kid
Please Input next operation:
write
Please input an character:
d
Write Operation:kidd
Please Input next operation:
del
Delete Operation:kid
Please Input next operation:
undo
UnDo Operation:kidd
Please Input next operation:
?
這兩個程序中需要有幾點說明:
1、????????????? 對于OperationCommand,我的理解是它所實現的Command只是某一個操作對于某一個接收者,所以我給它取名為OperationCommand。對于ObjectCommand,是實現這樣一種對象,它實現了請求接收者的所有操作,所以取名為ObjectCommand
2、????????????? 在代碼實例中,我對狀態的保存處理相對簡單,但這是因為利用了String對象的特點,當String對象被修改時,系統會重新分配一塊內存。不修改原內存上的內容。如果是要保存其他的引用類型應當注意使用深拷貝,否則,所保存的狀態對象都指向一個內存地址,隨著狀態的改變,保存不了原有的狀態。
3、????????????? 在對象狀態的保存上,我們可以使用Prototype模式。
Command模式的幾個要點:
1、? Command模式的根本目的在于將“行為請求者”與“行為實現者”解耦,在面向對象語言中,常見的實現手段是“將行為抽象為對象”。
2、? 實現Command接口的具體命令對象ConcreteCommand 有時候根據需要可能會保存一些額外的狀態信息。
3、? 通過使用Composite模式,可以將多個“命名”封裝為一個“復合命令”MacroCommand。
4、? Command模式與C#中的Delegate有些類似。但兩者定義行為接口的規范有所區別:Command以面向對象中的“接口-實現”類定義行為接口規范,更嚴格,更符合抽象原則:Delegate以函數簽名來定義行為接口規范,更靈活,但抽象能力比較弱
http://www.cnblogs.com/kid-li/category/44668.html
轉載于:https://www.cnblogs.com/xiayong123/p/3716998.html
總結
以上是生活随笔為你收集整理的设计模式学习笔记(十七)——Command命令模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: object-c 入门基础篇
- 下一篇: 用wordpress制作网站的总结