命令模式
将“请求”封装成对象,以便使用不同的请求,队列或日志来参数化其它对象。
命令模式也可以支持撤销的操作。
使用命令模式来实现“队列、日志、支持撤销操作”
===========================================================================
示例:遥控器功能的实现---开/关/撤销
接收命令的对象
package receiver; public abstract class Receiver { protected String location; }
package receiver.impl; import receiver.Receiver; /** * 灯 */ public class Light extends Receiver { public Light(String location) { this.location = location; } public void on() { System.out.println(location+"light on"); } public void off() { System.out.println(location+"light off"); } }
package receiver.impl; import receiver.Receiver; /** * 车库门 */ public class GarageDoor extends Receiver { public GarageDoor(String location) { this.location = location; } public void up() { System.out.println("Grarge Door is open"); } public void down() { System.out.println("Grarge Door is close"); } }
package receiver.impl; import receiver.Receiver; /** * 音响 */ public class Stereo extends Receiver { public Stereo(String location) { this.location = location; } public void on() { System.out.println("stereo is open,put cd in,set volume 11"); } public void off() { System.out.println("stereo off"); } }
各种具体的命令
package command; /** * 命令对象,对外只暴露execute(),内部如何执行外界无需关心 */ public abstract interface Command { //执行指令 public abstract void execute(); //撤销上一步操作 public abstract void undo(); }
package command.impl; import receiver.impl.Light; import command.Command; public class LightOffCommand implements Command { Light light; public LightOffCommand(Light light) { this.light = light; } @Override public void execute() { light.off(); } @Override public void undo() { light.on(); } }
package command.impl; import receiver.impl.Light; import command.Command; public class LightOnCommand implements Command { Light light; public LightOnCommand(Light light) { this.light = light; } @Override public void execute() { light.on(); } @Override public void undo() { light.off(); } }
package command.impl; import receiver.impl.GarageDoor; import command.Command; public class GarageDoorDownCommand implements Command { GarageDoor garageDoor; public GarageDoorDownCommand(GarageDoor garageDoor) { this.garageDoor = garageDoor; } @Override public void execute() { garageDoor.down(); } @Override public void undo() { garageDoor.up(); } }
package command.impl; import receiver.impl.GarageDoor; import command.Command; public class GarageDoorUpCommand implements Command { GarageDoor garageDoor; public GarageDoorUpCommand(GarageDoor garageDoor) { this.garageDoor = garageDoor; } @Override public void execute() { garageDoor.up(); } @Override public void undo() { garageDoor.down(); } }
package command.impl; import receiver.impl.Stereo; import command.Command; public class StereoOffCommand implements Command { Stereo stereo; public StereoOffCommand(Stereo stereo) { this.stereo = stereo; } @Override public void execute() { stereo.off(); } @Override public void undo() { stereo.on(); } }
package command.impl; import receiver.impl.Stereo; import command.Command; public class StereoOnWithCDCommand implements Command { Stereo stereo; public StereoOnWithCDCommand(Stereo stereo) { this.stereo = stereo; } @Override public void execute() { stereo.on(); } @Override public void undo() { stereo.off(); } }
命令调用者---Invoker
完成命令的绑定
负责将命令绑定到对应的具体对象上去执行
package controller; import java.util.Arrays; import command.Command; import command.NoCommand; /** * 遥控器---Invoker * 负责发出各种命令 */ public class RemoteController { //一组开的命令 Command[] onCommands; //一组关的命令 Command[] offCommands; //记录上次执行的命令,以便完成撤销 Command undoCommand; public RemoteController() { init(); } /** * 初始化遥控器 */ private void init() { onCommands = new Command[7];//看到没有,“接口也可以new”! offCommands = new Command[7]; Command noCommand = new NoCommand(); Arrays.fill(onCommands, noCommand); Arrays.fill(offCommands, noCommand); undoCommand = noCommand; } /** * 为每个插槽指定对应的命令对象 * @param slot 插槽序号 * @param onCommand 开 * @param offCommand 关 */ public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } /** * 事件触发,执行对应的命令 * @param slot 扩展槽序号 */ public void onButtonPressed(int slot) { onCommands[slot].execute();//执行命令 undoCommand = onCommands[slot];//记录本次执行的命令对象 } /** * 事件触发,执行对应的命令 * @param slot 扩展槽序号 */ public void offButtonPressed(int slot) { offCommands[slot].execute();//执行命令 undoCommand = offCommands[slot];//记录本次执行的命令对象 } /** * 撤销 */ public void undoButtonPressed() { undoCommand.undo(); } /** * 输出遥控器各个扩展槽所绑定的命令对象 */ public String toString() { StringBuffer stringBuff = new StringBuffer(); stringBuff.append("----- Remote Control ----\n"); for(int i=0; i<onCommands.length; i++) { stringBuff.append("[slot"+ i +"]" + onCommands[i].getClass().getName() + " " + offCommands[i].getClass().getName() + "\n"); } stringBuff.append("[undo]" + undoCommand.getClass().getName()); return stringBuff.toString(); } }
测试
package test; import receiver.impl.GarageDoor; import receiver.impl.Light; import receiver.impl.Stereo; import command.impl.GarageDoorDownCommand; import command.impl.GarageDoorUpCommand; import command.impl.LightOffCommand; import command.impl.LightOnCommand; import command.impl.StereoOffCommand; import command.impl.StereoOnWithCDCommand; import controller.RemoteController; public class RemoteLoader { public static void main(String[] args) { testCommand(); testUndo(); } private static void testCommand() { //Invoker---遥控器 RemoteController remoteController = new RemoteController(); //Receiver---各种被控制的对象 Light livingRoomLight = new Light("Living Room"); Light kitchenLight = new Light("Kitchen"); GarageDoor garageDoor = new GarageDoor(""); Stereo stereo = new Stereo("Living Room"); //为每个插槽绑定命令 remoteController.setCommand(0, new LightOnCommand(livingRoomLight), new LightOffCommand(livingRoomLight)); remoteController.setCommand(1, new LightOnCommand(kitchenLight), new LightOffCommand(kitchenLight)); remoteController.setCommand(2, new GarageDoorUpCommand(garageDoor), new GarageDoorDownCommand(garageDoor)); remoteController.setCommand(3, new StereoOnWithCDCommand(stereo), new StereoOffCommand(stereo)); //查看遥控器每个插槽所绑定的命令 System.out.println(remoteController); //测试遥控器插槽对应的命令 remoteController.onButtonPressed(0); remoteController.offButtonPressed(0); remoteController.onButtonPressed(1); remoteController.offButtonPressed(1); remoteController.onButtonPressed(2); remoteController.offButtonPressed(2); remoteController.onButtonPressed(3); remoteController.offButtonPressed(3); } private static void testUndo() { //Invoker---遥控器 RemoteController remoteController = new RemoteController(); //命令接收对象 Light livingRoomLight = new Light("Living Room"); //命令 LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight); LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight); //将卧室灯的命令绑定到0号插槽 remoteController.setCommand(0, livingRoomLightOn, livingRoomLightOff); remoteController.onButtonPressed(0);//开 remoteController.offButtonPressed(0);//关 System.out.println(remoteController); remoteController.undoButtonPressed();//撤销->开 remoteController.offButtonPressed(0);//关 remoteController.onButtonPressed(0);//开 remoteController.onButtonPressed(0);//开 System.out.println(remoteController); remoteController.undoButtonPressed(); } }
===========================================================================
使用状态实现撤销
package receiver.impl; import receiver.Receiver; public class CeilingFan extends Receiver{ public static final int HIGH = 3; public static final int MEDIUM = 2; public static final int LOW = 1; public static final int OFF = 0; int speed;//当前速度 public CeilingFan(String location) { this.location = location; } public void high() { speed = HIGH; System.out.println("高速狂转"); } public void medium() { speed = MEDIUM; System.out.println("中速转动"); } public void low() { speed = LOW; System.out.println("慢速转动"); } public void off() { speed = OFF; System.out.println("停止转动"); } public int getSpeed() { return speed; } }
package command.impl; import receiver.impl.CeilingFan; import command.Command; public class CeilingFanHighCommand implements Command { CeilingFan ceilingFan; int preSpeed;//上一次的速度【如果使用堆栈记录信息,可以实现多层次的撤销】 public CeilingFanHighCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } @Override public void execute() { preSpeed = ceilingFan.getSpeed(); run(CeilingFan.HIGH); } @Override public void undo() { run(preSpeed); } private void run(int speed) { switch(speed) { case CeilingFan.HIGH: ceilingFan.high(); break; case CeilingFan.MEDIUM: ceilingFan.medium(); break; case CeilingFan.LOW: ceilingFan.low(); break; case CeilingFan.OFF: ceilingFan.off(); break; } } }
package command.impl; import receiver.impl.CeilingFan; import command.Command; public class CeilingFanMediumCommand implements Command { CeilingFan ceilingFan; int preSpeed; public CeilingFanMediumCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } @Override public void execute() { preSpeed = ceilingFan.getSpeed(); run(CeilingFan.MEDIUM); } @Override public void undo() { run(preSpeed); } private void run(int speed) { switch(speed) { case CeilingFan.HIGH: ceilingFan.high(); break; case CeilingFan.MEDIUM: ceilingFan.medium(); break; case CeilingFan.LOW: ceilingFan.low(); break; case CeilingFan.OFF: ceilingFan.off(); break; } } }
package command.impl; import receiver.impl.CeilingFan; import command.Command; public class CeilingFanLowCommand implements Command { CeilingFan ceilingFan; int preSpeed; public CeilingFanLowCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } @Override public void execute() { preSpeed = ceilingFan.getSpeed(); run(CeilingFan.LOW); } @Override public void undo() { run(preSpeed); } private void run(int speed) { switch(speed) { case CeilingFan.HIGH: ceilingFan.high(); break; case CeilingFan.MEDIUM: ceilingFan.medium(); break; case CeilingFan.LOW: ceilingFan.low(); break; case CeilingFan.OFF: ceilingFan.off(); break; } } }
package command.impl; import receiver.impl.CeilingFan; import command.Command; public class CeilingFanOffCommand implements Command { CeilingFan ceilingFan; int preSpeed;//跟踪上一次的运行状态 public CeilingFanOffCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } @Override public void execute() { preSpeed = ceilingFan.getSpeed(); run(CeilingFan.OFF); } @Override public void undo() { run(preSpeed); } private void run(int speed) { switch(speed) { case CeilingFan.HIGH: ceilingFan.high(); break; case CeilingFan.MEDIUM: ceilingFan.medium(); break; case CeilingFan.LOW: ceilingFan.low(); break; case CeilingFan.OFF: ceilingFan.off(); break; } } }
测试
private static void testCeilingFan() { RemoteController invoker = new RemoteController(); CeilingFan ceilingFan = new CeilingFan("Living Room"); CeilingFanHighCommand ceilingHighCmd = new CeilingFanHighCommand(ceilingFan); CeilingFanMediumCommand ceilingMediumCmd = new CeilingFanMediumCommand(ceilingFan); CeilingFanLowCommand ceilingLowCmd = new CeilingFanLowCommand(ceilingFan); CeilingFanOffCommand ceilingOffCmd = new CeilingFanOffCommand(ceilingFan); invoker.setCommand(0, ceilingHighCmd, ceilingOffCmd); invoker.setCommand(1, ceilingMediumCmd, ceilingOffCmd); invoker.setCommand(2, ceilingLowCmd, ceilingOffCmd); invoker.onButtonPressed(0); invoker.offButtonPressed(0); invoker.undoButtonPressed(); invoker.onButtonPressed(2); invoker.onButtonPressed(1); invoker.undoButtonPressed(); }
===========================================================================
Party模式
把命令对象封装到一个数组中,完成命令的批量执行
package command.impl; import command.Command; /** * Party模式 * 宏命令:将一组命令集合起来,一起执行 */ public class MacroCommand implements Command { Command[] commands; public MacroCommand(Command[] commands) { this.commands = commands; } @Override public void execute() { for(Command c : commands) { c.execute(); } } @Override public void undo() { for(Command c : commands) { c.undo(); } } }
测试
private static void testMacroCommand() { RemoteController remoteController = new RemoteController(); Light light = new Light("Living Room"); Stereo stereo = new Stereo(""); CeilingFan ceilingFan = new CeilingFan("Living Room"); LightOnCommand lightOn = new LightOnCommand(light); StereoOnWithCDCommand stereoOn = new StereoOnWithCDCommand(stereo); CeilingFanMediumCommand celingFanMedium = new CeilingFanMediumCommand(ceilingFan); LightOffCommand lightOff = new LightOffCommand(light); StereoOffCommand stereoOff = new StereoOffCommand(stereo); CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); Command[] partyOn = {lightOn, stereoOn, celingFanMedium}; Command[] partyOff = {lightOff, stereoOff, ceilingFanOff}; MacroCommand partyOnMacro = new MacroCommand(partyOn); MacroCommand partyOffMacro = new MacroCommand(partyOff); remoteController.setCommand(0, partyOnMacro, partyOffMacro); // remoteController.onButtonPressed(0); remoteController.offButtonPressed(0); remoteController.undoButtonPressed(); }