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

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