設(shè)計(jì)模式學(xué)習(xí)總結(jié):命令模式
問題:
在面向?qū)ο蟮能浖O(shè)計(jì)中,經(jīng)常會(huì)遇到一個(gè)(或一系列)對(duì)象,對(duì)象本身的數(shù)據(jù)存儲(chǔ)與對(duì)象的操作耦合在一起。例如一個(gè)對(duì)象有add(),edit(),delete()方法,這樣對(duì)象支持的方法很難擴(kuò)展,如果需要加入update()就必須修改代碼,客戶端與對(duì)象也是緊耦合的。命令模式是將一類對(duì)象的功能(行為,功能)抽象成一個(gè)命令對(duì)象,客戶端在使用的時(shí)候,只與該命令對(duì)象打交道,而不用與對(duì)象打交道,分離命令的請(qǐng)求者和命令的執(zhí)行者,降低了耦合性,可以使用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化提高了程序設(shè)計(jì)的靈活性。
定義:
命令模式(Command)模式,將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤消的操作。
意圖:
提供一個(gè)抽象的Command接口,將執(zhí)行命令操作的方法封裝到Command類接口中,ConcreteCommand實(shí)現(xiàn)這個(gè)Command接口方法,通過調(diào)用Receiver實(shí)例變量處理請(qǐng)求。客戶端定義一個(gè)Invoker對(duì)象存儲(chǔ)該concreteCommand對(duì)象,該invoker通過調(diào)用command對(duì)象的遞交一個(gè)請(qǐng)求。
參與者:
•抽象命令角色(Command):
定義命令的接口,聲明執(zhí)行的方法。
具體命令角色(ConcreteCommand):
命令接口實(shí)現(xiàn)對(duì)象,是“虛”的實(shí)現(xiàn);通常會(huì)持有接收者,并調(diào)用接收者的功能來完成命令要執(zhí)行的操作?! ?/p>
•請(qǐng)求者(Invoker):
要求命令對(duì)象執(zhí)行請(qǐng)求,通常會(huì)持有命令對(duì)象,可以持有很多的命令對(duì)象。這個(gè)是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,也就是說相當(dāng)于使用命令對(duì)象的入口。
•接收者(Receiver、執(zhí)行者):
接收者,真正執(zhí)行命令的對(duì)象。任何類都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
•客戶端(Client):
創(chuàng)建具體的命令對(duì)象,并且設(shè)置命令對(duì)象的接收者。注意這個(gè)不是我們常規(guī)意義上的客戶端,而是在組裝命令對(duì)象和接收者,或許,把這個(gè)Client稱為裝配者會(huì)更好理解,因?yàn)檎嬲褂妹畹目蛻舳耸菑腎nvoker來觸發(fā)執(zhí)行。
UML圖:
實(shí)例說明:
諾基亞手機(jī)工廠
公司(Client)通知生產(chǎn)部(Invoker),生產(chǎn)兩部n8,兩部n9,生產(chǎn)部通過“命令模式”,將生產(chǎn)任務(wù)交給手機(jī)工廠(Receiver),生產(chǎn)手機(jī)。
uml圖如下:
- /// <summary>
- /// 手機(jī)生產(chǎn)命令接口(Command)
- /// </summary>
- public interface ICreatePhoneCommand
- {
- void Execute();
- }
- /// <summary>
- /// N8手機(jī)生產(chǎn)具體命令類(ConcreteCommand)
- /// </summary>
- public class CreateNokiaN8Command : ICreatePhoneCommand
- {
- PhoneFactory phoneFactory = null;
- public CreateNokiaN8Command(PhoneFactory _phoneFactory)
- {
- phoneFactory = _phoneFactory;
- }
- public void Execute()
- {
- phoneFactory.CreateNokiaN8();
- }
- }
- /// <summary>
- /// N8手機(jī)生產(chǎn)具體命令類(ConcreteCommand)
- /// </summary>
- public class CreateNokiaN9Command : ICreatePhoneCommand
- {
- PhoneFactory phoneFactory = null;
- public CreateNokiaN9Command(PhoneFactory _phoneFactory)
- {
- phoneFactory = _phoneFactory;
- }
- public void Execute()
- {
- phoneFactory.CreateNokiaN9();
- }
- }
- /// <summary>
- /// 手機(jī)生產(chǎn)工廠(Receiver)具體的手機(jī)生產(chǎn)
- /// </summary>
- public class PhoneFactory
- {
- public void CreateNokiaN8()
- {
- System.Console.WriteLine("一部Nokia N8 生產(chǎn)完成");
- }
- public void CreateNokiaN9()
- {
- System.Console.WriteLine("一部Nokia N9 生產(chǎn)完成");
- }
- }
- /// <summary>
- /// 生產(chǎn)部對(duì)象(Invoker)接收生產(chǎn)信息,制定生產(chǎn)清單。通知PhoneFactory生產(chǎn)
- /// </summary>
- public class LiaisonCreate
- {
- List<ICreatePhoneCommand> createPhoneCommandList = new List<ICreatePhoneCommand>();
- /// <summary>
- /// 添加生產(chǎn)任務(wù)
- /// </summary>
- /// <param name="_createPhoneCommand"></param>
- public void AddCreatePhoneTask(ICreatePhoneCommand _createPhoneCommand)
- {
- createPhoneCommandList.Add(_createPhoneCommand);
- }
- /// <summary>
- /// 撤銷生產(chǎn)任務(wù)
- /// </summary>
- /// <param name="_createPhoneCommand"></param>
- public void CancelCreatePhoneTask(ICreatePhoneCommand _createPhoneCommand)
- {
- createPhoneCommandList.Remove(_createPhoneCommand);
- }
- /// <summary>
- /// 執(zhí)行生產(chǎn)
- /// </summary>
- public void CreatePhone()
- {
- foreach (var createPhoneCommand in createPhoneCommandList)
- {
- createPhoneCommand.Execute();
- }
- }
- }
- public void CommandTest()
- {
- //初始化生產(chǎn)部聯(lián)系人
- LiaisonCreate liaisonCreate = new LiaisonCreate();
- //初始化生產(chǎn)工廠
- PhoneFactory phoneFactory = new PhoneFactory();
- //設(shè)置生產(chǎn)清單
- liaisonCreate.AddCreatePhoneTask(new CreateNokiaN8Command(phoneFactory));
- liaisonCreate.AddCreatePhoneTask(new CreateNokiaN8Command(phoneFactory));
- liaisonCreate.AddCreatePhoneTask(new CreateNokiaN9Command(phoneFactory));
- liaisonCreate.AddCreatePhoneTask(new CreateNokiaN9Command(phoneFactory));
- //取消一部N9的生產(chǎn)
- liaisonCreate.CancelCreatePhoneTask(new CreateNokiaN9Command(phoneFactory));
- //開始執(zhí)行生產(chǎn)
- liaisonCreate.CreatePhone();
- System.Console.Read();
- }
優(yōu)點(diǎn):
•命令模式將發(fā)出命令的責(zé)任和執(zhí)行命令的責(zé)任分割開,降低系統(tǒng)的耦合度?!?/p>
•新的命令可以很容易地加入到系統(tǒng)中。只要實(shí)現(xiàn)了抽象命令接口的具體命令類就可以與接收者相關(guān)聯(lián)?! ?/p>
•可以比較容易地設(shè)計(jì)一個(gè)組合命令,形成一個(gè)輕量級(jí)的事件隊(duì)列
•命令模式使請(qǐng)求本身成為一個(gè)對(duì)象,這個(gè)對(duì)象和其他對(duì)象一樣可以被存儲(chǔ)和傳遞。
•請(qǐng)求方不必知道接收請(qǐng)求的接口,執(zhí)行命令的細(xì)節(jié)(只需客戶端為concreteCommand對(duì)象指定一個(gè)receiver對(duì)象即可)起到了很好的封裝隔離作用.
缺點(diǎn):
•每一個(gè)命令都需要設(shè)計(jì)一個(gè)具體命令類,使用命令模式會(huì)導(dǎo)致某些系統(tǒng)有過多的具體命令類。
應(yīng)用情景:
•系統(tǒng)需要將請(qǐng)求調(diào)用者和請(qǐng)求接收者解耦,使得調(diào)用者和接收者不直接交互。
•系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)和執(zhí)行請(qǐng)求。
•系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(fù)(Redo)操作。
•系統(tǒng)需要將一組操作組合在一起,即支持宏命令。
原文鏈接:http://www.cnblogs.com/ejiyuan/archive/2012/06/28/2567905.html