上一次留給你們去作的實踐,不知道你們執行的怎麼樣了呢。java
咱們經過一個簡單的練習,完成了一個控制開關。那如今,咱們打算將遙控器的每一個插槽,對應到一個命令這樣就要遙控器變成「調用者」。當按下按鈕,相應命令對象的execute()方法就會被調用,其結果就是,接收者(例如電燈、風扇、音響)的動做被調用。程序員
public class RemoteControl { Command[] onCommands; Command[] offCommands; public RemoteControl() { onCommands = new Command[7]; offCommands = new Command[7]; // 在構造器中,只需實例化並初始化這兩個開與關的數組 Command noCommand = new NoCommand(); for (int i = 0; i < 7; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } } // 這個方法有三個參數,分別是插槽的位置、開的命令、關的命令。這些命令將記錄開關數組中對應的插槽位置,以供稍後使用 public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } // 當按下開或關的按鈕,硬件就會負責調用對應的方法,也就是onButtonWasPushed或offButtonWasPushed public void onButtonWasPushed(int slot) { onCommands[slot].execute(); } public void offButtonWasPushed(int slot) { offCommands[slot].execute(); } public String toString() { StringBuffer stringBuff = new StringBuffer(); stringBuff.append("\n------ Remote Control -------\n"); for (int i = 0; i < onCommands.length; i++) { stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() + " " + offCommands[i].getClass().getName() + "\n"); } return stringBuff.toString(); } }
此前咱們已經動手實現過LightOnCommand,純粹就是簡單的開和關命令。那如今,咱們來爲音響編寫開與關的命令。數組
音響的關閉是毫無難度,就是開啓的時候有點複雜,你知道爲何嗎?難道音響開了就行了?是否還須要後續其餘的動做才能讓音響響起來了?哎呀,小編多嘴了好像。app
public class StereoOnWithCDCommand implements Command { Stereo stereo; public StereoOnWithCDCommand(Stereo stereo) { this.stereo = stereo; } // 打開音響,須要三個步驟,開啓音響,設置CD播放,設置音量,否則就成啞吧了 public void execute() { stereo.on(); stereo.setCD(); stereo.setVolume(11); } }
這裏列舉了一個電燈,一個音響,差很少就把其餘相似的都已經搞定了,好比電扇、門,對吧。因此,趕忙看看你以前動手的操做,是否是和小編的差很少。學習
讓咱們繼續看下,多個的是怎麼實現的呢。測試
public class RemoteLoader { public static void main(String[] args) { RemoteControl remoteControl = new RemoteControl(); // 將全部的裝置建立在合適的位置 Light livingRoomLight = new Light("Living Room"); Light kitchenLight = new Light("Kitchen"); CeilingFan ceilingFan= new CeilingFan("Living Room"); GarageDoor garageDoor = new GarageDoor(""); Stereo stereo = new Stereo("Living Room"); // 建立全部的電燈命令對象 LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight); LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight); LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight); LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight); // 建立吊扇的開與關命令 CeilingFanOnCommand ceilingFanOn = new CeilingFanOnCommand(ceilingFan); CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); // 建立車庫門的上與下命令 GarageDoorUpCommand garageDoorUp = new GarageDoorUpCommand(garageDoor); GarageDoorDownCommand garageDoorDown = new GarageDoorDownCommand(garageDoor); // 建立音響的開與關命令 StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo); StereoOffCommand stereoOff = new StereoOffCommand(stereo); // 如今已經有了所有的命令,咱們將它們加載到遙控器插槽中 remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff); remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff); remoteControl.setCommand(3, stereoOnWithCD, stereoOff); System.out.println(remoteControl); // 在這裏逐步按下每一個插槽的開與關按鈕 remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); remoteControl.onButtonWasPushed(1); remoteControl.offButtonWasPushed(1); remoteControl.onButtonWasPushed(2); remoteControl.offButtonWasPushed(2); remoteControl.onButtonWasPushed(3); remoteControl.offButtonWasPushed(3); } }
咱們這個主要的設計目標就是讓遙控器代碼儘量地簡單,這樣一來,新的廠商類一旦出現,遙控器並不須要隨之修改。由於,咱們才用了命令模式,從邏輯上將遙控器的類和廠商的類解耦。咱們相信這將下降遙控器的生產成本,並大大地減小維護時所需的費用。this
下面的類圖提供了設計的全貌:設計
別急別急,小編說的功能都會有的。撤銷功能使用起來就是這樣的:好比說客廳的電燈是關閉的,而後你按下遙控器上的開啓按鈕,天然電燈就被打開了。如今若是按下撤銷按鈕,那麼上一個動做將被倒轉,在這個例子裏,電燈將被關閉。3d
一樣,咱們先來一個簡單的撤銷示例。以前咱們用的是execute()方法實現開啓或者關閉的調用,那麼咱們用undo()方法來執行撤銷操做。即在Command接口裏實現一個同execute()相反的方法undo(),而後在實現類裏將undo()的動做作成和execute()相反的操做便可。code
講的有點籠統?在這裏小編就不提供具體的代碼了,詳細的請看GitHub個人分享吧。
由於電燈這個開關已經撤銷,是很簡單的入門,小編沒有提供源碼在文中,可是由於還有電風扇這個存在,小編還不得不繼續搞一個高大上的方式。電扇不只僅是開關,還有檔位的存在,對吧,是否是瞬間有思路了呢?
public class CeilingFan { public static final int HIGH = 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; System.out.println(location + " ceiling fan is on high"); } public void medium() { speed = MEDIUM; System.out.println(location + " ceiling fan is on medium"); } public void low() { speed = LOW; System.out.println(location + " ceiling fan is on low"); } public void off() { speed = OFF; System.out.println(location + " ceiling fan is off"); } public int getSpeed() { return speed; } }
如今咱們就來實現風扇的撤銷。這麼作,須要追蹤吊扇的最後設置速度,若是undo方法被調用了,就要恢復成以前吊扇速度的設置值。就以下面這樣:
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(); } } }
條件都具有了,那咱們來測試下吧。咱們打算把0號插槽的開啓按鈕設置爲中速,把第1號插槽的開啓按鈕設置成高速,代碼以下:
public class RemoteLoader { public static void main(String[] args) { RemoteControlWithUndo remoteControl = new RemoteControlWithUndo(); CeilingFan ceilingFan = new CeilingFan("Living Room"); CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan); CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan); CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff); remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff); // 首先,咱們以中速開啓吊扇 remoteControl.onButtonWasPushed(0); // 而後關閉 remoteControl.offButtonWasPushed(0); System.out.println(remoteControl); // 撤銷,應該會回到中速 remoteControl.undoButtonWasPushed(); // 這個時候開啓高速 remoteControl.onButtonWasPushed(1); System.out.println(remoteControl); // 再進行一次撤銷,應該會回到中速 remoteControl.undoButtonWasPushed(); } }
好了,至此咱們不只僅實現了單個的開與關,還實現了一整個遙控器全部控件的開與關,甚至是複雜的家電的開與關(音響、電扇的開啓略複雜),並且均實現了撤銷。做爲程序員的你是否是常用撤銷功能呢,反正我是常用的噢。
可是,這還不是終極狀態。咱們在這裏只能實現一個家電的開與關,若是光憑按下一個按鈕,不能實現燈光、電視、音響的同步使用,那這個遙控器對咱們來講是否是仍是有點low呢?是吧,確實有點low,如何破解,敬請期待咱們的下一篇。
愛生活,愛學習,愛感悟,愛挨踢