设计模式目录:
概述
第1部分 问题引入
首先看下,下面的要求:
实现命令接口
首先,让说有的命令对象实现相同的包含一个方法的接口。
1 /** 2 * 命令接口 3 * @ClassName: Command 4 * @author Xingle 5 * @date 2014-9-11 上午10:13:46 6 */ 7 public interface Command { 8 public void execute(); 9 }
实现一个打开电灯的命令
在实现打开电灯或者关闭电灯之前,先看下灯的类
1 public class Light { 2 3 public Light(){} 4 5 //开灯 6 public void on(){ 7 System.out.println("Light is on"); 8 } 9 10 //关灯 11 public void off(){ 12 System.out.println("Light is off"); 13 } 14 }
接着开灯以及关灯命令:
1 /** 2 * 实现一个开灯命令 3 * @ClassName: LightOnCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午10:25:19 7 */ 8 public class LightOnCommand implements Command{ 9 10 Light light; 11 12 public LightOnCommand(Light light){ 13 this.light = light; 14 } 15 16 @Override 17 public void execute() { 18 light.on(); 19 } 20 21 }
1 /** 2 * 实现一个关灯命令 3 * @ClassName: LightOffCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午10:55:35 7 */ 8 public class LightOffCommand implements Command{ 9 10 Light light; 11 12 public LightOffCommand(Light light){ 13 this.light = light; 14 }; 15 16 @Override 17 public void execute() { 18 light.off(); 19 } 20 21 }
使用命令对象
假设我们有一个遥控器,它只有一个按钮和对应的插槽,可以控制一个装置:
1 // 2 //This is the invoker 3 // 4 public class SimpleRemoteControl { 5 //一个插槽持有命令,控制着一个装置 6 Command slot; 7 8 public SimpleRemoteControl(){}; 9 10 //这个方法用来设置插槽控制的命令。如果客户想要改变遥控器按钮的行为,可以多次调用这个方法 11 public void setCommand(Command command){ 12 slot = command; 13 } 14 //当按下按钮时,这个方法就会被调用,使得当前命令衔接插槽,并调用它的execute()方法 15 public void buttonWasPressed(){ 16 slot.execute(); 17 } 18 }
下面再多加一个控制车库门的命令,车库门以及命令如下:
1 /** 2 * 车库门 3 * @ClassName: GarageDoor 4 * @author Xingle 5 * @date 2014-9-11 上午10:53:15 6 */ 7 public class GarageDoor { 8 public GarageDoor() { 9 } 10 11 public void up() { 12 System.out.println("Garage Door is Open"); 13 } 14 15 public void down() { 16 System.out.println("Garage Door is Closed"); 17 } 18 19 public void stop() { 20 System.out.println("Garage Door is Stopped"); 21 } 22 23 public void lightOn() { 24 System.out.println("Garage light is on"); 25 } 26 27 public void lightOff() { 28 System.out.println("Garage light is off"); 29 } 30 }
1 /** 2 * 开车库门命令 3 * @ClassName: GarageDoorOpenCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午10:53:52 7 */ 8 public class GarageDoorOpenCommand implements Command{ 9 10 GarageDoor garageDoor; 11 12 public GarageDoorOpenCommand(GarageDoor garageDoor) { 13 this.garageDoor = garageDoor; 14 } 15 16 @Override 17 public void execute() { 18 garageDoor.up(); 19 } 20 }
遥控器使用的简单测试:
1 /** 2 * 遥控器的测试程序 3 * @ClassName: RemoteControlTest 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午10:57:38 7 */ 8 public class RemoteControlTest { 9 public static void main(String[] args){ 10 //遥控器就是调用者,会传入一个命令对象,可以用来发出请求 11 SimpleRemoteControl remote = new SimpleRemoteControl(); 12 13 //创建了一个电灯对象,也就是请求的接受者 14 Light light = new Light(); 15 GarageDoor garageDoor = new GarageDoor(); 16 //创建一个命令,然后将接受者传给它 17 LightOnCommand lightOn = new LightOnCommand(light); 18 GarageDoorOpenCommand garageOpen = new GarageDoorOpenCommand(garageDoor); 19 20 //把命令传给调用者 21 remote.setCommand(lightOn); 22 //模拟按下按钮 23 remote.buttonWasPressed(); 24 25 remote.setCommand(garageOpen); 26 remote.buttonWasPressed(); 27 } 28 }
执行结果:
第2部分 定义和实现
命令模式 将“请求”封装成对象,以便使用不用的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
一个命令对象通过在特定接受者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接受者包进对象中。这个对象只暴露一个execute() 方法,当此方法被调用的时候,接收者就会进行这些动作。从外面看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute() 方法,请求的目的就能达到。
将命令指定到插槽
将遥控器的每个插槽,对应到一个命令,这样就让遥控器变成“调用者”。当按下按钮,相应的命令对象的execute() 方法就会被调用,其结果是,接收者(例如:电灯、音响,电扇)的动作被调用。
实现遥控器
1 /** 2 * 带有撤销的遥控器 3 * @ClassName: RemoteControlWithUndo 4 * @author Xingle 5 * @date 2014-9-11 下午12:18:47 6 */ 7 public class RemoteControlWithUndo { 8 9 Command[] onCommands; 10 Command[] offCommands; 11 //前一个命令将被记录在这里 12 Command undoCommand; 13 14 public RemoteControlWithUndo() { 15 //遥控器要处理7个开与关的命令,使用相应数组记录这些命令 16 onCommands = new Command[7]; 17 offCommands = new Command[7]; 18 //空对象 19 Command noCommand = new NoCommand(); 20 21 for (int i = 0; i < 7; i++) { 22 onCommands[i] = noCommand; 23 offCommands[i] = noCommand; 24 } 25 undoCommand = noCommand; 26 } 27 28 public void setCommand(int slot, Command onCommand, Command offCommand) { 29 onCommands[slot] = onCommand; 30 offCommands[slot] = offCommand; 31 } 32 33 public void onButtonWasPushed(int slot) { 34 onCommands[slot].execute(); 35 undoCommand = onCommands[slot]; 36 } 37 38 public void offButtonWasPushed(int slot) { 39 offCommands[slot].execute(); 40 undoCommand = offCommands[slot]; 41 } 42 43 public void undoButtonWasPushed() { 44 undoCommand.undo(); 45 } 46 47 public String toString() { 48 StringBuffer stringBuff = new StringBuffer(); 49 stringBuff.append("\n------ Remote Control -------\n"); 50 for (int i = 0; i < onCommands.length; i++) { 51 stringBuff.append("[slot " + i + "] " 52 + onCommands[i].getClass().getName() + " " 53 + offCommands[i].getClass().getName() + "\n"); 54 } 55 stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n"); 56 return stringBuff.toString(); 57 } 58 59 }
命令接口
1 public interface Command { 2 3 public void execute(); 4 5 //撤销操作 6 public void undo(); 7 8 }
灯 的类
1 /** 2 * 灯 3 * @ClassName: Light 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午11:52:57 7 */ 8 public class Light { 9 String location = ""; 10 11 public Light(String location) { 12 this.location = location; 13 } 14 15 public void on() { 16 System.out.println(location + " light is on"); 17 } 18 19 public void off() { 20 System.out.println(location + " light is off"); 21 } 22 }
实现命令
1 /** 2 * 开灯 3 * @ClassName: LightOnCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午11:52:18 7 */ 8 public class LightOnCommand implements Command{ 9 Light light ; 10 11 public LightOnCommand(Light light){ 12 this.light = light; 13 } 14 @Override 15 public void execute() { 16 light.on(); 17 } 18 @Override 19 public void undo() { 20 light.off(); 21 } 22 23 }
1 /** 2 * 关灯 3 * @ClassName: LightOffCommand 4 * @author Xingle 5 * @date 2014-9-11 下午12:00:05 6 */ 7 public class LightOffCommand implements Command { 8 9 Light light; 10 11 public LightOffCommand(Light light) { 12 this.light = light; 13 } 14 15 @Override 16 public void execute() { 17 light.off(); 18 } 19 20 @Override 21 public void undo() { 22 light.on(); 23 } 24 25 }
音响
1 /** 2 * 音响 3 * @ClassName: Stereo 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午11:54:46 7 */ 8 public class Stereo { 9 10 String location; 11 12 public Stereo(String location) { 13 this.location = location; 14 } 15 16 public void on() { 17 System.out.println(location + " stereo is on"); 18 } 19 20 public void off() { 21 System.out.println(location + " stereo is off"); 22 } 23 24 public void setCD() { 25 System.out.println(location + " stereo is set for CD input"); 26 } 27 28 public void setDVD() { 29 System.out.println(location + " stereo is set for DVD input"); 30 } 31 32 public void setRadio() { 33 System.out.println(location + " stereo is set for Radio"); 34 } 35 36 public void setVolume(int volume) { 37 System.out.println(location + " Stereo volume set to " + volume); 38 } 39 40 }
音响的命令操作
1 /** 2 * 开音响 3 * @ClassName: StereoOnWithCDCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 上午11:54:19 7 */ 8 public class StereoOnWithCDCommand implements Command{ 9 10 Stereo stereo; 11 12 public StereoOnWithCDCommand(Stereo stereo) { 13 this.stereo = stereo; 14 } 15 16 @Override 17 public void execute() { 18 stereo.on(); 19 } 20 21 @Override 22 public void undo() { 23 stereo.off(); 24 } 25 26 }
1 /** 2 * 关音响 3 * @ClassName: StereoOffCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午12:03:02 7 */ 8 public class StereoOffCommand implements Command{ 9 Stereo stereo; 10 11 public StereoOffCommand(Stereo stereo) { 12 this.stereo = stereo; 13 } 14 15 @Override 16 public void execute() { 17 stereo.off(); 18 } 19 20 @Override 21 public void undo() { 22 stereo.on(); 23 } 24 25 }
吊扇
1 /** 2 * 吊扇 3 * 4 * @ClassName: CeilingFan 5 * @author Xingle 6 * @date 2014-9-11 下午12:36:04 7 */ 8 public class CeilingFan { 9 10 11 public static final int HIGH = 3; 12 public static final int MEDIUM = 2; 13 public static final int LOW = 1; 14 public static final int OFF = 0; 15 String location; 16 int speed; 17 18 public CeilingFan(String location) { 19 this.location = location; 20 speed = OFF; 21 } 22 23 //高速 24 public void high() { 25 speed = HIGH; 26 System.out.println(location + " ceiling fan is on high"); 27 } 28 //中速 29 public void medium() { 30 speed = MEDIUM; 31 System.out.println(location + " ceiling fan is on medium"); 32 } 33 //低速 34 public void low() { 35 speed = LOW; 36 System.out.println(location + " ceiling fan is on low"); 37 } 38 //关闭 39 public void off() { 40 speed = OFF; 41 System.out.println(location + " ceiling fan is off"); 42 } 43 44 public int getSpeed() { 45 return speed; 46 } 47 48 }
电扇的三个命令,分别把电扇开到高速,中速,和低速
1 /** 2 * 开电扇到高速 3 * @ClassName: CeilingFanHighCommand 4 * @author Xingle 5 * @date 2014-9-11 下午12:37:20 6 */ 7 public class CeilingFanHighCommand implements Command { 8 9 CeilingFan ceilingFan; 10 int prevSpeed; 11 12 public CeilingFanHighCommand(CeilingFan ceilingFan) { 13 this.ceilingFan = ceilingFan; 14 } 15 16 @Override 17 public void execute() { 18 prevSpeed = ceilingFan.getSpeed(); 19 ceilingFan.high(); 20 } 21 22 @Override 23 public void undo() { 24 if (prevSpeed == CeilingFan.HIGH) { 25 ceilingFan.high(); 26 } else if (prevSpeed == CeilingFan.MEDIUM) { 27 ceilingFan.medium(); 28 } else if (prevSpeed == CeilingFan.LOW) { 29 ceilingFan.low(); 30 } else if (prevSpeed == CeilingFan.OFF) { 31 ceilingFan.off(); 32 } 33 } 34 35 }
1 /** 2 * 开电扇到中速 3 * @ClassName: CeilingFanMediumCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午12:39:57 7 */ 8 public class CeilingFanMediumCommand implements Command{ 9 CeilingFan ceilingFan; 10 int prevSpeed; 11 12 public CeilingFanMediumCommand(CeilingFan ceilingFan) { 13 this.ceilingFan = ceilingFan; 14 } 15 @Override 16 public void execute() { 17 prevSpeed = ceilingFan.getSpeed(); 18 ceilingFan.medium(); 19 } 20 21 @Override 22 public void undo() { 23 if (prevSpeed == CeilingFan.HIGH) { 24 ceilingFan.high(); 25 } else if (prevSpeed == CeilingFan.MEDIUM) { 26 ceilingFan.medium(); 27 } else if (prevSpeed == CeilingFan.LOW) { 28 ceilingFan.low(); 29 } else if (prevSpeed == CeilingFan.OFF) { 30 ceilingFan.off(); 31 } 32 } 33 }
1 /** 2 * 开电扇到低速 3 * @ClassName: CeilingFanLowCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午12:38:25 7 */ 8 public class CeilingFanLowCommand implements Command{ 9 10 CeilingFan ceilingFan; 11 int prevSpeed; 12 13 public CeilingFanLowCommand(CeilingFan ceilingFan) { 14 this.ceilingFan = ceilingFan; 15 } 16 17 @Override 18 public void execute() { 19 prevSpeed = ceilingFan.getSpeed(); 20 ceilingFan.low(); 21 } 22 23 @Override 24 public void undo() { 25 if (prevSpeed == CeilingFan.HIGH) { 26 ceilingFan.high(); 27 } else if (prevSpeed == CeilingFan.MEDIUM) { 28 ceilingFan.medium(); 29 } else if (prevSpeed == CeilingFan.LOW) { 30 ceilingFan.low(); 31 } else if (prevSpeed == CeilingFan.OFF) { 32 ceilingFan.off(); 33 } 34 } 35 36 }
关电扇命令
1 /** 2 * 关电扇 3 * @ClassName: CeilingFanOffCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午12:45:18 7 */ 8 public class CeilingFanOffCommand implements Command{ 9 10 CeilingFan ceilingFan; 11 int prevSpeed; 12 13 public CeilingFanOffCommand(CeilingFan ceilingFan) { 14 this.ceilingFan = ceilingFan; 15 } 16 17 @Override 18 public void execute() { 19 prevSpeed = ceilingFan.getSpeed(); 20 ceilingFan.off(); 21 } 22 23 @Override 24 public void undo() { 25 if (prevSpeed == CeilingFan.HIGH) { 26 ceilingFan.high(); 27 } else if (prevSpeed == CeilingFan.MEDIUM) { 28 ceilingFan.medium(); 29 } else if (prevSpeed == CeilingFan.LOW) { 30 ceilingFan.low(); 31 } else if (prevSpeed == CeilingFan.OFF) { 32 ceilingFan.off(); 33 } 34 } 35 36 }
测试遥控器
1 /** 2 * 测试程序 3 * 4 * @ClassName: RemoteLoader 5 * @author Xingle 6 * @date 2014-9-11 上午11:57:26 7 */ 8 public class RemoteLoader { 9 public static void main(String[] args) { 10 11 RemoteControlWithUndo remoteControl = new RemoteControlWithUndo(); 12 13 Light livingRoomLight = new Light("Living Room"); 14 15 CeilingFan ceilingFan = new CeilingFan("ww Room"); 16 17 18 19 LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight); 20 LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight); 21 22 CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan); 23 CeilingFanLowCommand ceilingFanLow = new CeilingFanLowCommand(ceilingFan); 24 CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan); 25 CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); 26 27 // 28 remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); 29 remoteControl.setCommand(1, ceilingFanMedium, ceilingFanOff); 30 remoteControl.setCommand(2, ceilingFanHigh, ceilingFanOff); 31 32 remoteControl.onButtonWasPushed(0); 33 remoteControl.offButtonWasPushed(0); 34 System.out.println(remoteControl); 35 remoteControl.undoButtonWasPushed(); 36 37 remoteControl.onButtonWasPushed(1);//中速开 38 remoteControl.offButtonWasPushed(1);//关闭 39 System.out.println(remoteControl); 40 remoteControl.undoButtonWasPushed();//撤销,会回到中速 41 42 remoteControl.onButtonWasPushed(2);//高度开 43 System.out.println(remoteControl);// 44 remoteControl.undoButtonWasPushed();//撤销,回到中速 45 } 46 47 }
执行结果:
Living Room light is on
Living Room light is off
------ Remote Control -------
[slot 0] firsthead.command.remote.LightOnCommand firsthead.command.remote.LightOffCommand
[slot 1] firsthead.command.remote.CeilingFanMediumCommand firsthead.command.remote.CeilingFanOffCommand
[slot 2] firsthead.command.remote.CeilingFanHighCommand firsthead.command.remote.CeilingFanOffCommand
[slot 3] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 4] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 5] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 6] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[undo] firsthead.command.remote.LightOffCommand
Living Room light is on
ww Room ceiling fan is on medium
ww Room ceiling fan is off
------ Remote Control -------
[slot 0] firsthead.command.remote.LightOnCommand firsthead.command.remote.LightOffCommand
[slot 1] firsthead.command.remote.CeilingFanMediumCommand firsthead.command.remote.CeilingFanOffCommand
[slot 2] firsthead.command.remote.CeilingFanHighCommand firsthead.command.remote.CeilingFanOffCommand
[slot 3] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 4] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 5] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 6] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[undo] firsthead.command.remote.CeilingFanOffCommand
ww Room ceiling fan is on medium
ww Room ceiling fan is on high
------ Remote Control -------
[slot 0] firsthead.command.remote.LightOnCommand firsthead.command.remote.LightOffCommand
[slot 1] firsthead.command.remote.CeilingFanMediumCommand firsthead.command.remote.CeilingFanOffCommand
[slot 2] firsthead.command.remote.CeilingFanHighCommand firsthead.command.remote.CeilingFanOffCommand
[slot 3] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 4] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 5] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[slot 6] firsthead.command.remote.NoCommand firsthead.command.remote.NoCommand
[undo] firsthead.command.remote.CeilingFanHighCommand
ww Room ceiling fan is on medium
第3部分 使用宏命令
宏命令(macro command), 即多个命令的组合操作。
1 /** 2 * 宏命令 3 * @ClassName: MacroCommand 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午3:09:38 7 */ 8 public class MacroCommand implements Command{ 9 10 Command[] commands; 11 12 public MacroCommand(Command[] commands) { 13 this.commands = commands; 14 } 15 16 @Override 17 public void execute() { 18 for (int i = 0; i < commands.length; i++) { 19 commands[i].execute(); 20 } 21 } 22 23 @Override 24 public void undo() { 25 for (int i = commands.length -1; i >= 0; i--) { 26 commands[i].undo(); 27 } 28 } 29 30 }
1 /** 2 * 遥控 3 * @ClassName: RemoteControl 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午3:04:43 7 */ 8 public class RemoteControl { 9 Command[] onCommands; 10 Command[] offCommands; 11 Command undoCommand; 12 13 public RemoteControl() { 14 onCommands = new Command[7]; 15 offCommands = new Command[7]; 16 17 Command noCommand = new NoCommand(); 18 for(int i=0;i<7;i++) { 19 onCommands[i] = noCommand; 20 offCommands[i] = noCommand; 21 } 22 undoCommand = noCommand; 23 } 24 25 public void setCommand(int slot, Command onCommand, Command offCommand) { 26 onCommands[slot] = onCommand; 27 offCommands[slot] = offCommand; 28 } 29 30 public void onButtonWasPushed(int slot) { 31 onCommands[slot].execute(); 32 undoCommand = onCommands[slot]; 33 } 34 35 public void offButtonWasPushed(int slot) { 36 offCommands[slot].execute(); 37 undoCommand = offCommands[slot]; 38 } 39 40 public void undoButtonWasPushed() { 41 undoCommand.undo(); 42 } 43 44 public String toString() { 45 StringBuffer stringBuff = new StringBuffer(); 46 stringBuff.append("\n------ Remote Control -------\n"); 47 for (int i = 0; i < onCommands.length; i++) { 48 stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() 49 + " " + offCommands[i].getClass().getName() + "\n"); 50 } 51 stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n"); 52 return stringBuff.toString(); 53 } 54 }
测试程序:
1 /** 2 * 带宏的测试程序 3 * @ClassName: RemoteLoader 4 * TODO 5 * @author Xingle 6 * @date 2014-9-11 下午3:04:18 7 */ 8 public class RemoteLoader { 9 public static void main(String[] args) { 10 11 RemoteControl remoteControl = new RemoteControl(); 12 Light light = new Light("Living Room"); 13 Stereo stereo = new Stereo("Living Room"); 14 15 LightOnCommand lightOn = new LightOnCommand(light); 16 StereoOnCommand stereoOn = new StereoOnCommand(stereo); 17 LightOffCommand lightOff = new LightOffCommand(light); 18 StereoOffCommand stereoOff = new StereoOffCommand(stereo); 19 20 //一个数组记录开启命令 21 Command[] partyOn = { lightOn, stereoOn}; 22 //一个数组记录关闭命令 23 Command[] partyOff = { lightOff, stereoOff}; 24 25 /** 26 * 创建两个对应的宏持有它们 27 */ 28 MacroCommand partyOnMacro = new MacroCommand(partyOn); 29 MacroCommand partyOffMacro = new MacroCommand(partyOff); 30 31 //将宏命令指定给一个按钮 32 remoteControl.setCommand(0, partyOnMacro, partyOffMacro); 33 34 System.out.println(remoteControl); 35 System.out.println("--- Pushing Macro On---"); 36 remoteControl.onButtonWasPushed(0); 37 System.out.println("--- Pushing Macro Off---"); 38 remoteControl.offButtonWasPushed(0); 39 } 40 }
执行结果:
------ Remote Control -------
[slot 0] firsthead.command.party.MacroCommand firsthead.command.party.MacroCommand
[slot 1] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[slot 2] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[slot 3] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[slot 4] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[slot 5] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[slot 6] firsthead.command.party.NoCommand firsthead.command.party.NoCommand
[undo] firsthead.command.party.NoCommand
--- Pushing Macro On---
Light is on
Living Room stereo is on
--- Pushing Macro Off---
Light is off
Living Room stereo is off