http://blog.sina.com.cn/s/blog_5016113a01009rta.html
命令模式定義
??? 將“請(qǐng)求”封裝成對(duì)象,以便使用不同的請(qǐng)求、隊(duì)列或者日志來(lái)參數(shù)化其他對(duì)象。命令模式也支持可撤銷(xiāo)的操作
命令模式可以將“動(dòng)作的請(qǐng)求者”和“動(dòng)作的執(zhí)行者”分隔開(kāi)來(lái)(解耦)
例子:設(shè)計(jì)一個(gè)家電自動(dòng)化遙控器的API。遙控器有七個(gè)插頭,可以連接不同的家電電器,每個(gè)插頭有對(duì)應(yīng)的開(kāi)關(guān)按鈕,用來(lái)控制電器的開(kāi)關(guān)。這個(gè)遙控器還具備一個(gè)整體的撤銷(xiāo)按鈕。
解析:
當(dāng)遙控器按下“開(kāi)”按鈕時(shí),直接調(diào)用家用電器的“開(kāi)”方法。但是有很多家用電器,每種家用電器的“開(kāi)”方法名稱(chēng)也不一定相同,這意味著每一個(gè)插頭的“開(kāi)”按鈕按下時(shí),都要判斷是什么家用電器,然后再調(diào)用它的“開(kāi)”方法。
使用命令模式:
封裝方法調(diào)用,把方法調(diào)用封裝成對(duì)象。把每種家用電器的 “開(kāi)”方法和執(zhí)行“開(kāi)”方法的電器封裝成一個(gè)統(tǒng)一標(biāo)準(zhǔn)的對(duì)象,遙控器通過(guò)操作統(tǒng)一標(biāo)準(zhǔn)的對(duì)象,來(lái)操作家用電器,就可以忽略每種家用電器之間的差異。
UML圖(點(diǎn)擊看大圖)
UML圖解
Light為電燈類(lèi),LightOnCommand封裝了Light和Light的on()方法,它符合Command的標(biāo)準(zhǔn)。遙控器通過(guò)操作Command來(lái)操作家用電器,從而忽略多種家用電器之間的差異。
為遙控器實(shí)現(xiàn)撤銷(xiāo)(undo)按鈕
例子:遙控天花板吊扇,風(fēng)扇有風(fēng)速檔位(low、medium、hight),并且要實(shí)現(xiàn)撤銷(xiāo)按鈕,即打開(kāi)風(fēng)扇,撤銷(xiāo)后就關(guān)閉風(fēng)扇,讓風(fēng)扇回到打開(kāi)前狀態(tài)。
UML圖
UML圖解
RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
CeilingFan ceilingFan = new CeilingFan("Living Room");? //在客廳天花板上的吊扇
CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);??
//把風(fēng)扇調(diào)到中檔,這是個(gè)“開(kāi)”命令
CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); //關(guān)閉風(fēng)扇命令??????????
remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);??????????
remoteControl.onButtonWasPushed(0);??????? //按下“開(kāi)”
remoteControl.offButtonWasPushed(0);??????? //按下“關(guān)”
remoteControl.undoButtonWasPushed();??????? //按下 “撤銷(xiāo)”
NoCommand對(duì)象
NoCommand是一個(gè)空對(duì)象(null object),當(dāng)你不想返回一個(gè)有意義的對(duì)象時(shí),空對(duì)象就很有用。空對(duì)象可以避免我們?cè)诔绦蛑袑?xiě)上判斷對(duì)象是否為空的if等語(yǔ)句。
Party模式
按下一個(gè)按鈕,就同時(shí)能打開(kāi)音響、電燈、電視、設(shè)置好DVD,并讓熱水器開(kāi)始加溫。
設(shè)計(jì)一個(gè)“宏”命令類(lèi)
RemoteControl remoteControl = new RemoteControl();??
Command[] partyOn = {…………};??????? //一組“開(kāi)”命令
Command[] partyOff = { ………...};??????? //一組“關(guān)”命令
MacroCommand partyOnMacro = new MacroCommand(partyOn);? //初始化宏命令
MacroCommand partyOffMacro = new MacroCommand(partyOff);
remoteControl.setCommand(0, partyOnMacro, partyOffMacro);
remoteControl.onButtonWasPushed(0);??????? //執(zhí)行一組“開(kāi)”命令
remoteControl.offButtonWasPushed(0);
如何學(xué)現(xiàn)多層次的撤銷(xiāo)操作?
使用一個(gè)堆棧記錄操作過(guò)程的每一個(gè)命令,按撤銷(xiāo)時(shí)從堆棧(后進(jìn)先出)中取出最上層的命令,調(diào)用它的undo方法。
命令模式的更多用途
1.隊(duì)列請(qǐng)求
把一組命令放到隊(duì)列(先進(jìn)先出)中,線程從隊(duì)列中一個(gè)一個(gè)刪除命令,然后調(diào)用它的excecute()方法。
2.日志請(qǐng)求
把所有動(dòng)作都記錄在日志中,在系統(tǒng)發(fā)生錯(cuò)誤時(shí),重新調(diào)用這些動(dòng)作恢復(fù)到之前的狀態(tài)
Command Pattern的適用場(chǎng)景
1.使用命令模式作為"CallBack"在面向?qū)ο笙到y(tǒng)中的替代。"CallBack"講的便是先將一個(gè)函數(shù)登記上,然后在以后調(diào)用此函數(shù)。
2.需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)。一個(gè)命令對(duì)象和原先的請(qǐng)求發(fā)出者可以有不同的生命期。換言之,原先的請(qǐng)求發(fā)出者可能已經(jīng)不在了,而命令對(duì)象本身仍然是活動(dòng)的。這時(shí)命令的接收者可以是在本地,也可以在網(wǎng)絡(luò)的另外一個(gè)地址。命令對(duì)象可以在串形化之后傳送到另外一臺(tái)機(jī)器上去。
3.系統(tǒng)需要支持命令的撤消(undo)。命令對(duì)象可以把狀態(tài)存儲(chǔ)起來(lái),等到客戶(hù)端需要撤銷(xiāo)命令所產(chǎn)生的效果時(shí),可以調(diào)用undo()方法,把命令所產(chǎn)生的效果撤銷(xiāo)掉。命令對(duì)象還可以提供redo()方法,以供客戶(hù)端在需要時(shí),再重新實(shí)施命令效果。
4.如果一個(gè)系統(tǒng)要將系統(tǒng)中所有的數(shù)據(jù)更新到日志里,以便在系統(tǒng)崩潰時(shí),可以根據(jù)日志里讀回所有的數(shù)據(jù)更新命令,重新調(diào)用Execute()方法一條一條執(zhí)行這些命令,從而恢復(fù)系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。
總結(jié)
Command模式是非常簡(jiǎn)單而又優(yōu)雅的一種設(shè)計(jì)模式,它的根本目的在于將“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”解耦。
命令模式定義
??? 將“請(qǐng)求”封裝成對(duì)象,以便使用不同的請(qǐng)求、隊(duì)列或者日志來(lái)參數(shù)化其他對(duì)象。命令模式也支持可撤銷(xiāo)的操作
命令模式可以將“動(dòng)作的請(qǐng)求者”和“動(dòng)作的執(zhí)行者”分隔開(kāi)來(lái)(解耦)
例子:設(shè)計(jì)一個(gè)家電自動(dòng)化遙控器的API。遙控器有七個(gè)插頭,可以連接不同的家電電器,每個(gè)插頭有對(duì)應(yīng)的開(kāi)關(guān)按鈕,用來(lái)控制電器的開(kāi)關(guān)。這個(gè)遙控器還具備一個(gè)整體的撤銷(xiāo)按鈕。
解析:
當(dāng)遙控器按下“開(kāi)”按鈕時(shí),直接調(diào)用家用電器的“開(kāi)”方法。但是有很多家用電器,每種家用電器的“開(kāi)”方法名稱(chēng)也不一定相同,這意味著每一個(gè)插頭的“開(kāi)”按鈕按下時(shí),都要判斷是什么家用電器,然后再調(diào)用它的“開(kāi)”方法。
使用命令模式:
封裝方法調(diào)用,把方法調(diào)用封裝成對(duì)象。把每種家用電器的 “開(kāi)”方法和執(zhí)行“開(kāi)”方法的電器封裝成一個(gè)統(tǒng)一標(biāo)準(zhǔn)的對(duì)象,遙控器通過(guò)操作統(tǒng)一標(biāo)準(zhǔn)的對(duì)象,來(lái)操作家用電器,就可以忽略每種家用電器之間的差異。
UML圖(點(diǎn)擊看大圖)
UML圖解
Light為電燈類(lèi),LightOnCommand封裝了Light和Light的on()方法,它符合Command的標(biāo)準(zhǔn)。遙控器通過(guò)操作Command來(lái)操作家用電器,從而忽略多種家用電器之間的差異。
//1.Command接口形式: public interface Command { public void execute(); } //2.LightOnCommand形式: public class LightOnCommand implements Command { Light light; //封裝方法執(zhí)行者 public LightOnCommand(Light light) { this.light = light; } public void execute() { light.on(); //封裝方法 } } //3.SimpleRemoteControl遙控器形式如: public class SimpleRemoteControl { Command slot; public SimpleRemoteControl() {} public void setCommand(Command command) { slot = command; } public void buttonWasPressed() { slot.execute(); //遙控器不知道方法執(zhí)行者到底是誰(shuí),它操作統(tǒng)一家用標(biāo)準(zhǔn)Command對(duì)象。 } } //4.實(shí)際動(dòng)作方式: SimpleRemoteControl remote = new SimpleRemoteControl(); Light light = new Light(); LightOnCommand lightOn = new LightOnCommand(light); //封裝電燈“開(kāi)”方法的對(duì)象。 remote.setCommand(lightOn); //把統(tǒng)一標(biāo)準(zhǔn)對(duì)象放入遙控器 remote.buttonWasPressed();????????
為遙控器實(shí)現(xiàn)撤銷(xiāo)(undo)按鈕
例子:遙控天花板吊扇,風(fēng)扇有風(fēng)速檔位(low、medium、hight),并且要實(shí)現(xiàn)撤銷(xiāo)按鈕,即打開(kāi)風(fēng)扇,撤銷(xiāo)后就關(guān)閉風(fēng)扇,讓風(fēng)扇回到打開(kāi)前狀態(tài)。
UML圖
UML圖解
1.CeilingFan為天花板風(fēng)扇類(lèi),包含開(kāi)關(guān)、調(diào)檔等方式 public class CeilingFan { public static final int HIGH = 3; //風(fēng)速檔位為3檔 public static final int MEDIUM = 2; public static final int LOW = 1; public static final int OFF = 0; String location; //天花板的位置 int speed; //當(dāng)前風(fēng)速檔位 public CeilingFan(String location) { this.location = location; speed = OFF; } public void high() { speed = HIGH; } public void medium() { speed = MEDIUM; } public void low() { speed = LOW; } public void off() { speed = OFF; } public int getSpeed() { return speed; } } 2.Command接口,家用電器執(zhí)行/撤銷(xiāo)動(dòng)作標(biāo)準(zhǔn) public interface Command { public void execute(); //執(zhí)行某個(gè)動(dòng)作 public void undo(); //撤銷(xiāo)execute()要執(zhí)行的動(dòng)作 } 3.CeilingFanHighCommand類(lèi),包含風(fēng)扇調(diào)為最高檔位,和撤銷(xiāo)到原來(lái)狀態(tài)的方法 public class CeilingFanHighCommand implements Command { CeilingFan ceilingFan; int prevSpeed; //當(dāng)前風(fēng)速 public CeilingFanHighCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } public void execute() { prevSpeed = ceilingFan.getSpeed(); //調(diào)為最高風(fēng)速前,記下當(dāng)時(shí)的風(fēng)速,用于撤銷(xiāo)動(dòng)作 ceilingFan.high(); } public void undo() { //撤銷(xiāo)動(dòng)作 if (prevSpeed == CeilingFan.HIGH) { //如果先前是最高風(fēng)速,撤銷(xiāo)當(dāng)前的動(dòng)作,把風(fēng)速調(diào)到最高。 ceilingFan.high(); } else if (prevSpeed == CeilingFan.MEDIUM) { ceilingFan.medium(); } else if (prevSpeed == CeilingFan.LOW) { ceilingFan.low(); } else if (prevSpeed == CeilingFan.OFF) { ceilingFan.off(); } } } 4.RemoteControlWithUndo為遙控器類(lèi) public class RemoteControlWithUndo { Command[] onCommands; //封裝所有“開(kāi)”命令,遙控器有7個(gè)開(kāi)關(guān) Command[] offCommands; Command undoCommand; //當(dāng)前的命令 public RemoteControlWithUndo() { onCommands = new Command[7]; //初始化7個(gè)開(kāi)與關(guān)命令,命令為noCommand對(duì)象,它什么都不做 offCommands = new Command[7]; Command noCommand = new NoCommand(); for(int i=0;i<7;i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } undoCommand = noCommand; } public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonWasPushed(int slot) { //打開(kāi)“開(kāi)關(guān)” onCommands[slot].execute(); undoCommand = onCommands[slot]; //記錄當(dāng)前的命令 } public void offButtonWasPushed(int slot) { //關(guān)閉“開(kāi)關(guān)” offCommands[slot].execute(); undoCommand = offCommands[slot]; } public void undoButtonWasPushed() { undoCommand.undo(); } }實(shí)際動(dòng)作方式:
RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
CeilingFan ceilingFan = new CeilingFan("Living Room");? //在客廳天花板上的吊扇
CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);??
//把風(fēng)扇調(diào)到中檔,這是個(gè)“開(kāi)”命令
CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); //關(guān)閉風(fēng)扇命令??????????
remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);??????????
remoteControl.onButtonWasPushed(0);??????? //按下“開(kāi)”
remoteControl.offButtonWasPushed(0);??????? //按下“關(guān)”
remoteControl.undoButtonWasPushed();??????? //按下 “撤銷(xiāo)”
NoCommand對(duì)象
NoCommand是一個(gè)空對(duì)象(null object),當(dāng)你不想返回一個(gè)有意義的對(duì)象時(shí),空對(duì)象就很有用。空對(duì)象可以避免我們?cè)诔绦蛑袑?xiě)上判斷對(duì)象是否為空的if等語(yǔ)句。
Party模式
按下一個(gè)按鈕,就同時(shí)能打開(kāi)音響、電燈、電視、設(shè)置好DVD,并讓熱水器開(kāi)始加溫。
設(shè)計(jì)一個(gè)“宏”命令類(lèi)
public class MacroCommand implements Command { Command[] commands; //使用命令數(shù)組存儲(chǔ)一大堆命令 public MacroCommand(Command[] commands) { this.commands = commands; } public void execute() { //這個(gè)宏命令被遙控器執(zhí)行時(shí),就一次性執(zhí)行數(shù)組中的每一個(gè)命令 for (int i = 0; i < commands.length; i++) { commands[i].execute(); } } public void undo() { //撤銷(xiāo)宏命令,我認(rèn)為應(yīng)是:for (int i = commands.length-1; i >0; i--) for (int i = 0; i < commands.length; i++) { commands[i].undo(); } } }實(shí)際動(dòng)作方式
RemoteControl remoteControl = new RemoteControl();??
Command[] partyOn = {…………};??????? //一組“開(kāi)”命令
Command[] partyOff = { ………...};??????? //一組“關(guān)”命令
MacroCommand partyOnMacro = new MacroCommand(partyOn);? //初始化宏命令
MacroCommand partyOffMacro = new MacroCommand(partyOff);
remoteControl.setCommand(0, partyOnMacro, partyOffMacro);
remoteControl.onButtonWasPushed(0);??????? //執(zhí)行一組“開(kāi)”命令
remoteControl.offButtonWasPushed(0);
如何學(xué)現(xiàn)多層次的撤銷(xiāo)操作?
使用一個(gè)堆棧記錄操作過(guò)程的每一個(gè)命令,按撤銷(xiāo)時(shí)從堆棧(后進(jìn)先出)中取出最上層的命令,調(diào)用它的undo方法。
命令模式的更多用途
1.隊(duì)列請(qǐng)求
把一組命令放到隊(duì)列(先進(jìn)先出)中,線程從隊(duì)列中一個(gè)一個(gè)刪除命令,然后調(diào)用它的excecute()方法。
2.日志請(qǐng)求
把所有動(dòng)作都記錄在日志中,在系統(tǒng)發(fā)生錯(cuò)誤時(shí),重新調(diào)用這些動(dòng)作恢復(fù)到之前的狀態(tài)
Command Pattern的適用場(chǎng)景
1.使用命令模式作為"CallBack"在面向?qū)ο笙到y(tǒng)中的替代。"CallBack"講的便是先將一個(gè)函數(shù)登記上,然后在以后調(diào)用此函數(shù)。
2.需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)。一個(gè)命令對(duì)象和原先的請(qǐng)求發(fā)出者可以有不同的生命期。換言之,原先的請(qǐng)求發(fā)出者可能已經(jīng)不在了,而命令對(duì)象本身仍然是活動(dòng)的。這時(shí)命令的接收者可以是在本地,也可以在網(wǎng)絡(luò)的另外一個(gè)地址。命令對(duì)象可以在串形化之后傳送到另外一臺(tái)機(jī)器上去。
3.系統(tǒng)需要支持命令的撤消(undo)。命令對(duì)象可以把狀態(tài)存儲(chǔ)起來(lái),等到客戶(hù)端需要撤銷(xiāo)命令所產(chǎn)生的效果時(shí),可以調(diào)用undo()方法,把命令所產(chǎn)生的效果撤銷(xiāo)掉。命令對(duì)象還可以提供redo()方法,以供客戶(hù)端在需要時(shí),再重新實(shí)施命令效果。
4.如果一個(gè)系統(tǒng)要將系統(tǒng)中所有的數(shù)據(jù)更新到日志里,以便在系統(tǒng)崩潰時(shí),可以根據(jù)日志里讀回所有的數(shù)據(jù)更新命令,重新調(diào)用Execute()方法一條一條執(zhí)行這些命令,從而恢復(fù)系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。
總結(jié)
Command模式是非常簡(jiǎn)單而又優(yōu)雅的一種設(shè)計(jì)模式,它的根本目的在于將“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”解耦。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
