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ì)您有幫助就好】元

