上一次留给你们去作的实践,不知道你们执行的怎么样了呢。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,如何破解,敬请期待咱们的下一篇。
爱生活,爱学习,爱感悟,爱挨踢