1.声明
设计模式中的设计思想、图片和部分代码参考自《Head First设计模式》,作者Eric Freeman & Elisabeth Freeman & Kathy Siezza & Bert Bates。
在这里我只是对这本书进行学习阅读,并向大家分享一些心得体会。
2.需求
巴斯特家电自动化公司,主要的营业项目是向客户兜售自己的家电产品,并且这些家电都是受软件控制的,例如可以用软件打开客厅的电灯,但是最近巴斯特公司有了新的需求,新的需求是需要用一个遥控器来控制这些家电,例如,遥控器上可以控制客厅的灯的开启和关闭,并且将这个需求委托我们来做,作为回报,我们能够得到巴斯特公司的股票期权。
补充:巴斯特公司会给我们提供各个家电的API(API包括开启和关闭等功能)。
遥控器模型样例:
厂商提供的各个家电的API:
由API的接口可以看出,各个家电的接口并不统一,而且繁杂。
按照以往的设计思路,我们仍然希望遥控器和各个家电之间解耦,即遥控器不需要知道将要执行的是哪个家电,遥控器只管通知就可以了,所以一旦进行解耦,我们的代码中就不会出现大量的if else语句,因为我们知道,if else非常不利于维护吗,日后新增家电类型,我们还需要修改if else语句。
避免if-else,类似于:
public void excute(Command c) {
if(c == LightOn) {
//开灯
light.on();
}else if(c == LightOff) {
//关灯
light.off();
}else if(c == FanOn) {
//开风扇
fan.off();
}
}
3.命令模式
命令模式可将“动作的请求者”从”动作的执行者“对象中解耦。在这里请求者就是遥控器,执行者就是家电。
3.1借鉴餐厅的运作方式
我们在接触命令模式之前,先来研究一下餐厅的运作方式,或许我们能够得到一些启发。
餐厅的点餐流程:
以程序的角度描述餐厅的点餐流程:
流程描述:
把订单想象成一个用来准备点餐的对象,订单接口只包含一个方法,就是orderUP(),这个方法封装了准备点餐所需的动作。订单内有一个到"需要进行准备工作的对象”,即厨师的引用。所以女招待员不需要知道订单上有什么,也不需要知道谁来准备餐点,只需要将订单拿过来,然后放在订单窗口,然后大叫一声"订单来了"即可。
一天内,有不同的订单,这会使得招待员的takeOrder()方法传入不同的参数。女招待员知道所有的订单支持orderUP方法,需要烹饪餐点时,调用订单的orderUP()即可。
厨师具备烹饪餐点的只是,他知道如何准备餐点,一旦女招待员调用订单的orderUP(),厨师就开始烹饪。厨师和招待员之间是解耦的,二者不需要直接沟通,依赖于订单交流。
类比于家电系统:
遥控器的插槽是招待员,家电是厨师。
注:遥控器目前拥有七个可编程插槽,每个插槽都指向一个家用电器。
3.2程序实现
3.2.1命令模式样例
完成整个需求的代码肯定是较复杂所以我们先从简单的入手,先让遥控器能够控制电灯的开关。(注:这也是我在日常工作和学习中经常使用的方法,即设计一个系统,先用简单的方式跑通,然后再实现细节,就像汽车会先制造框架,素描画人时会先画轮廓一样)。
由于遥控器上的按钮会发出各种各样的命令,那么首先需要建立一个命令接口,来描述命令的特征。
电器-灯:
//家电-灯
public class Light {
public Light() {
}
public void on() {
System.out.println("开灯");
}
public void off() {
System.out.println("关灯");
}
}
命令接口:
public interface Command {
//这个excute方法就是餐厅的订单的orderUP方法
public void excute();
}
根据厂商提供的电灯的API,电灯一共有两个方法,分别是on()和off()。
开灯命令:
//开灯命令
public class LightOnCommand implements Command {
//命令类中持有命令接收者对象的引用
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
//开灯,低层由Light去完成
@Override
public void execute() {
light.on();
}
}
仅支持开灯的遥控器(暂时使用):
/*
* 命令的调用者:遥控器
* 这里对遥控器的代码做了简化,只有一个按钮,为了测试开灯命令
*/
public class SimpleRemoteControl {
//命令对象的引用
Command slot;
public SimpleRemoteControl() {}
public void setCommand(Command command) {
slot = command;
}
//按下按钮,即执行命令
public void buttonWasPressed() {
slot.execute();
}
}
测试:
public class RemoteControlTest {
public static void main(String[] args) {
//创建遥控器对象
SimpleRemoteControl remote = new SimpleRemoteControl();
//创建家电-灯
Light light = new Light();
//创建开灯的命令
LightOnCommand lightOn = new LightOnCommand(light);
//遥控器设置此命令,并且执行命令
remote.setCommand(lightOn);
remote.buttonWasPressed();
}
}
输出结果:
开灯
3.2.2命令模式的定义
命令模式
将"请求"封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
定义解析:
一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute方法,当此方法被调用的时候,接收者就会知道这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了那些动作,只知道如果调用execute方法,请求的目的就达到了。
餐厅就是利用命令来参数化对象的一些例子。一整天下来,女招待员参数化许多订单。在简单遥控器中,我们先用一个"打开电灯"命令加载按钮插槽,同理我们也可以将命令替换成为另一个"打开车库门"这样的命令。就和女招待员一样,遥控器插槽根本不在乎所拥有的是什么命令,只要将命令对象实现了Command接口就可以了。
命令模式类图:
3.2.3程序的真正实现
实现遥控器:
实现遥控器之前,有两点需要注意一下:
- 每个电器都有最基本的开关按钮,那么电器的"开"命令和电器的"关"命令应该分开存储。
- 为了区分厨房和客厅的电灯,那么灯的开关命令下应该持有对应房间(厨房|客厅)的灯对象。
那么其实对于灯这个电器来说,它其实是有4中命令的(假设只有厨房和客厅有灯),厨房开灯命令,厨房关灯命令,客厅开灯命令,客厅关灯命令。
设计方案是,让遥控器的每个插槽对应一个命令。
===================================遥控器代码===================================
真正的遥控器代码:
//调用者,遥控器对象
public class RemoteControl {
//装在七个插槽的"开"命令
Command[] onCommands;
//装在七个插槽的"关"命令
Command[] offCommands;
//初始化
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
//初始化时为所有按钮设置默认命令:noCommand
Command noCommand = new NoCommand();
for (int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
//设置命令 slot:插槽的位置[1,7] onCommand:开命令 offCommand:关命令
public void setCommand(int slot, Command onCommand, Command offCommand) {
//设置开关命令在相应位置
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
//对应插槽位置的开命令调用
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();
}
}
程序为没有设置命令的插槽赋予了空命令NoCommand,这样做避免了程序中的null判断。
===================================电器代码===================================
电器-灯:参考3.2.1代码
电器-吊扇:
//电器-吊扇
public class CeilingFan {
String location = "";
//吊扇转速级别
int level;
public static final int HIGH = 2; //高速
public static final int MEDIUM = 1; //中速
public static final int LOW = 0; //低速
public CeilingFan(String location) {
this.location = location;
}
public void high() {
level = HIGH;
System.out.println(location + " 设置转速为高速");
}
public void medium() {
level = MEDIUM;
System.out.println(location + " 设置转速为中速");
}
public void low() {
level = LOW;
System.out.println(location + " 设置转速为低速");
}
public void off() {
level = 0;
System.out.println(location + " 关闭");
}
//获取吊扇转速
public int getSpeed() {
return level;
}
}
电器-车库门:
// 电器-车库门
public class GarageDoor {
String location;
public GarageDoor(String location) {
this.location = location;
}
public void up() {
System.out.println(location + " 升起");
}
public void down() {
System.out.println(location + " 降落");
}
public void stop() {
System.out.println(location + " 停止");
}
public void lightOn() {
System.out.println(location + " 开灯");
}
public void lightOff() {
System.out.println(location + " 关灯");
}
}
电器-音响:
//电器-音响
public class Stereo {
//电器描述
String location;
public Stereo(String location) {
this.location = location;
}
public void on() {
System.out.println(location + " 开启");
}
public void off() {
System.out.println(location + " 关闭");
}
public void setCD() {
System.out.println(location + " 放入CD");
}
public void setDVD() {
System.out.println(location + " 放入DVD");
}
public void setRadio() {
System.out.println(location + " 开启收音机");
}
public void setVolume(int volume) {
System.out.println(location + " 将声音大小设置为: " + volume);
}
}
===================================遥命令代码===================================
关灯命令:
//关灯命令
public class LightOffCommand implements Command {
//命令接收者的引用
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
//底层由命令接收者去完成动作
light.off();
}
}
音响用CD开启命令:
//音响放入CD开启命令
public class StereoOnWithCDCommand implements Command {
Stereo stereo;
public StereoOnWithCDCommand(Stereo stereo) {
this.stereo = stereo;
}
public void execute() {
//音响开机
stereo.on();
//放入CD
stereo.setCD();
//设置音量为11
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); //音响播放CD
StereoOffCommand stereoOff =
new StereoOffCommand(stereo); //音响关闭
//将命令设置到遥控器的相应插槽中
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);
remoteControl.setCommand(3, garageDoorUp, garageDoorDown);
remoteControl.setCommand(4, 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);
remoteControl.onButtonWasPushed(4);
remoteControl.offButtonWasPushed(4);
}
}
输出结果:
------ Remote Control -------
[slot 0] command.LightOnCommand command.LightOffCommand
[slot 1] command.LightOnCommand command.LightOffCommand
[slot 2] command.CeilingFanOnCommand command.CeilingFanOffCommand
[slot 3] command.GarageDoorUpCommand command.GarageDoorDownCommand
[slot 4] command.StereoOnWithCDCommand command.StereoOffCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
Living Room 开启
Living Room 关闭
Kitchen 开启
Kitchen 关闭
Living Room 设置转速为高速
Living Room 关闭
升起
升起
Living Room 开启
Living Room 放入CD
Living Room 将声音大小设置为: 11
Living Room 关闭
3.2.4撤销功能
撤销功能:
如果一开始客厅的灯是关闭的,那么当你按下开灯按钮,那么等会打开,这时,如果按下撤销按钮,那么会撤销最后一次对灯的操作,即撤销"开灯"这个操作,这时候灯就被关闭了。
修改命令接口,定义撤销方法:
public interface Command {
//这个execute方法就是餐厅的订单的orderUP方法
public void execute();
//3.2.4新增:撤销最近一次的操作
public void undo();
}
修改开灯命令:
//开灯命令
public class LightOnCommand implements Command {
//命令类中持有命令接收者对象的引用
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
//开灯,低层由Light去完成
@Override
public void execute() {
light.on();
}
//3.2.4新增:撤销开灯命令
@Override
public void undo() {
light.off();
}
}
修改关灯命令:
//关灯命令
public class LightOffCommand implements Command {
//命令接收者的引用
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
//底层由命令接收者去完成动作
light.off();
}
//3.2.4新增撤销关灯命令
@Override
public void undo() {
light.on();
}
}
对于遥控器来说,想要撤销最后一步的命令,那么最起码应该知道遥控器的最后一次命令是哪个,所以我们需要新增一个变量来记录最后一次的命令。
遥控器代码:
//调用者,遥控器对象
public class RemoteControl {
//装在七个插槽的"开"命令
Command[] onCommands;
//装在七个插槽的"关"命令
Command[] offCommands;
//3.2.4新增:记录最后一次操作的命令
Command undoCommand;
//初始化
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
//初始化时为所有按钮设置默认命令:noCommand
Command noCommand = new NoCommand();
for (int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
//3.2.4新增:初始化最后一次的命令,开始时无命令,赋值为空对象
undoCommand = noCommand;
}
//设置命令 slot:插槽的位置[1,7] onCommand:开命令 offCommand:关命令
public void setCommand(int slot, Command onCommand, Command offCommand) {
//设置开关命令在相应位置
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
//对应插槽位置的开命令调用
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
//3.2.4新增:更新undoCommand
undoCommand = onCommands[slot];
}
//对应插槽位置的关命令调用
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
//3.2.4新增:更新undoCommand
undoCommand = offCommands[slot];
}
//3.2.4新增:当撤销按钮被按下时,这时候调用命令的撤销方法
public void undoButtonWasPushed() {
undoCommand.undo();
}
//打印出插槽的位置和开关命令
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();
}
}
撤销-电灯部分的测试代码:
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light livingRoomLight = new Light("Living Room");
LightOnCommand livingRoomLightOn =
new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff =
new LightOffCommand(livingRoomLight);
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
System.out.println(remoteControl);
remoteControl.undoButtonWasPushed();
remoteControl.offButtonWasPushed(0);
remoteControl.onButtonWasPushed(0);
System.out.println(remoteControl);
remoteControl.undoButtonWasPushed();
}
}
输出结果:
Living Room 开启
Living Room 关闭
------ Remote Control -------
[slot 0] command.LightOnCommand command.LightOffCommand
[slot 1] command.NoCommand command.NoCommand
[slot 2] command.NoCommand command.NoCommand
[slot 3] command.NoCommand command.NoCommand
[slot 4] command.NoCommand command.NoCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
Living Room 开启
Living Room 关闭
Living Room 开启
------ Remote Control -------
[slot 0] command.LightOnCommand command.LightOffCommand
[slot 1] command.NoCommand command.NoCommand
[slot 2] command.NoCommand command.NoCommand
[slot 3] command.NoCommand command.NoCommand
[slot 4] command.NoCommand command.NoCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
Living Room 关闭
下面看看吊扇这种多状态的命令如何实现撤销。
家电-吊扇:
//电器-吊扇
public class CeilingFan {
String location = "";
//吊扇转速级别
int level;
public static final int HIGH = 3; //高速
public static final int MEDIUM = 2; //中速
public static final int LOW = 1; //低俗
public static final int OFF = 0;
public CeilingFan(String location) {
this.location = location;
}
public void high() {
level = HIGH;
System.out.println(location + " 设置转速为高速");
}
public void medium() {
level = MEDIUM;
System.out.println(location + " 设置转速为中速");
}
public void low() {
level = LOW;
System.out.println(location + " 设置转速为低速");
}
public void off() {
level = OFF;
System.out.println(location + " 关闭");
}
//获取吊扇转速
public int getSpeed() {
return level;
}
}
吊扇高速转动命令:
//吊扇高速转动命令
public class CeilingFanHighCommand implements Command {
CeilingFan ceilingFan;
//记录本次高速命令之前的命令
int prevSpeed;
public CeilingFanHighCommand(CeilingFan ceilingFan) {
this.ceilingFan = ceilingFan;
}
public void execute() {
prevSpeed = ceilingFan.getSpeed();
ceilingFan.high();
}
//判断最后一次操作的命令prevSpeed是什么,从而回滚到之前的速度
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();
}
}
}
吊扇中速转动命令:
//吊扇中速转动命令
public class CeilingFanMediumCommand implements Command {
CeilingFan ceilingFan;
int prevSpeed;
public CeilingFanMediumCommand(CeilingFan ceilingFan) {
this.ceilingFan = ceilingFan;
}
public void execute() {
prevSpeed = ceilingFan.getSpeed();
ceilingFan.medium();
}
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();
}
}
}
吊扇关闭转动的命令:
public class CeilingFanOffCommand implements Command {
CeilingFan ceilingFan;
int prevSpeed;
public CeilingFanOffCommand(CeilingFan ceilingFan) {
this.ceilingFan = ceilingFan;
}
public void execute() {
prevSpeed = ceilingFan.getSpeed();
ceilingFan.off();
}
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();
}
}
}
测试代码:
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
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();
}
}
输出结果:
Living Room 设置转速为中速
Living Room 关闭
------ Remote Control -------
[slot 0] command.CeilingFanMediumCommand command.CeilingFanOffCommand
[slot 1] command.CeilingFanHighCommand command.CeilingFanOffCommand
[slot 2] command.NoCommand command.NoCommand
[slot 3] command.NoCommand command.NoCommand
[slot 4] command.NoCommand command.NoCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
Living Room 设置转速为中速
Living Room 设置转速为高速
------ Remote Control -------
[slot 0] command.CeilingFanMediumCommand command.CeilingFanOffCommand
[slot 1] command.CeilingFanHighCommand command.CeilingFanOffCommand
[slot 2] command.NoCommand command.NoCommand
[slot 3] command.NoCommand command.NoCommand
[slot 4] command.NoCommand command.NoCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
Living Room 设置转速为中速
3.2.5Party模式
由于一个一个的操控电器太麻烦,现在我们需要一个party模式,就是一键就可以让各个电器达到我们要求的状态,例如:客厅灯打开、客厅吊扇打开、电视打开等这一系列操作一步完成,并且在现有架构就能完成,那么如何才能实现呢?
首先我们知道,之前的命令类,都只能执行一种动作,那么如果我们定义一个命令类,该类可以一步(excute)执行多种动作,那么party模式是不是就能实现了呢?
定义宏命令类:
//宏命令类
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--) {
commands[i].undo();
}
}
}
线面我们用宏命令实现这样的功能,按下开启按钮时,打开客厅的灯,并将客厅吊扇设置为高速;按下关闭按钮时,将客厅灯设置为关闭,并且将客厅吊扇设置为中速(注:这里就不设计复杂的party命令了,因为思想相同)。
测试party模式:
//party命令测试类
public class RemoteLoader {
public static void main(String[] args) {
//初始化遥控器
RemoteControl remoteControl = new RemoteControl();
Light light = new Light("Living Room");
CeilingFan ceilingFan = new CeilingFan("Living Room");
LightOnCommand lightOn = new LightOnCommand(light);
CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
LightOffCommand lightOff = new LightOffCommand(light);
CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
// partyOn:开灯并使吊扇高速转动
Command[] partyOn = { lightOn, ceilingFanHigh};
// partyOff:关灯并使吊扇中速转动
Command[] partyOff = { lightOff, ceilingFanMedium};
//初始化MacroCommand,以命令数组作为参数
MacroCommand partyOnMacro = new MacroCommand(partyOn);
MacroCommand partyOffMacro = new MacroCommand(partyOff);
//在遥控器的第一个按钮处设置party命令
remoteControl.setCommand(0, partyOnMacro, partyOffMacro);
System.out.println(remoteControl);
System.out.println("--- Pushing Macro On---");
remoteControl.onButtonWasPushed(0);
System.out.println("--- Pushing Macro Off---");
remoteControl.offButtonWasPushed(0);
}
}
输出结果:
------ Remote Control -------
[slot 0] command.MacroCommand command.MacroCommand
[slot 1] command.NoCommand command.NoCommand
[slot 2] command.NoCommand command.NoCommand
[slot 3] command.NoCommand command.NoCommand
[slot 4] command.NoCommand command.NoCommand
[slot 5] command.NoCommand command.NoCommand
[slot 6] command.NoCommand command.NoCommand
--- Pushing Macro On---
Living Room 开启
Living Room 设置转速为高速
--- Pushing Macro Off---
Living Room 关闭
Living Room 设置转速为中速
4.总结
4.1补充说明
- 之所以不讲接收者的处理逻辑写在调用者中,原因是:分开写更符合解耦的原则。
- 宏命令初始化时,传入的参数是命令数组,命令数组存在的意义是,可以动态的订制宏命令。
4.2命令模式的其他用途
4.2.1队列请求
4.2.2日志请求