命令模式:
将 “请求” 封装成对象,以便使用不同的请求、队列或者日志来参与参数化其他对象。命令模式也支持可撤销的操作。
- 命令模式将发出请求的对象和执行请求的对象解耦。
- 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。
- 调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。
- 调用者可以接受命令当作参数,甚至在运行时动态地进行。
- 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。
- 宏命令是命令的一种简单的延续,允许调用多个命令。宏方法也可以支持撤销。
- 实际操作时,很常见使用“聪明”命令对象,也就直接实现了请求,而不是将工作委托给接收者。
- 命令也可以用来实现日志和事务系统。
/** * @Description: 命令模式-命令接口 * @date 2018/4/9 22:54 */ public interface Command { /** * 执行 */ void execute(); /** * 撤销 */ void undo(); }
public class Light { public Light(String weizhi) { System.out.println("位置 = [" + weizhi + "]"); } public void on(){ System.out.println(".....打开"); } public void off(){ System.out.println("..........关闭"); } }
public class LightOffCommand implements Command{ Light light; /** * 构造器传入了某个电灯,以便让这个命令控制,然后记录在实例变量中。 * 一旦调用execute(),就由这个电灯对象成为接收者,负责接收请求。 * @param light */ public LightOffCommand(Light light) { this.light = light; } public void execute() { light.off(); } public void undo() { light.on(); } }
public class LightOnCommand implements Command{ Light light; /** * 构造器传入了某个电灯,以便让这个命令控制,然后记录在实例变量中。 * 一旦调用execute(),就由这个电灯对象成为接收者,负责接收请求。 * @param light */ public LightOnCommand(Light light) { this.light = light; } public void execute() { light.on(); } public void undo() { light.off(); } }
public class StereoOffCommand implements Command{ Stereo stereo; public StereoOffCommand(Stereo stereo) { this.stereo = stereo; } public void execute() { stereo.off(); } public void undo() { } }
public class StereoOnWithCDCommand implements Command{ Stereo stereo; public StereoOnWithCDCommand(Stereo stereo) { this.stereo = stereo; } /** * 执行后会调用3个方法 * 打开、播放cd、音量调到11 */ public void execute() { stereo.on(); stereo.setCd(); stereo.setVolume(11); } public void undo() { } }
/** * @Description: 空对象,当你不想返回一个有意义的对象时,空对象很有用。 * @date 2018/4/10 20:45 */ public class NoCommand implements Command{ public void execute() { } public void undo() { } }
public class RemoteControl { //遥控器处理7个开与关的命令,使用相应的数组记录命令 Command[] onCommands; Command[] offCommands; Command undoCommand; 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; } 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 onButtonWasPushed(int slot){ onCommands[slot].execute(); undoCommand = onCommands[slot]; } /** * 按下关按钮就会调用相应的方法 * @param slot */ public void offButtonWasPushed(int slot){ offCommands[slot].execute(); undoCommand = offCommands[slot]; } /** * 撤销按钮 */ public void undoButtonWasPushed(){ undoCommand.undo(); } @Override public String toString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("\n--------Remote Control -----------\n"); for (int i = 0; i < onCommands.length; i++) { stringBuffer.append("[slot"+i+"]"+onCommands[i].getClass().getName()+" "+offCommands[i].getClass().getName()+"\n"); } return stringBuffer.toString(); } }
public class SimpleRemoteControl { Command slot; public SimpleRemoteControl() {} public void setCommand(Command command){ slot = command; } public void buttonWasPressed(){ slot.execute(); } }
public class Test { 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); remoteControl.undoButtonWasPushed(); System.out.println("--------------------------------"); remoteControl.offButtonWasPushed(0); remoteControl.onButtonWasPushed(0); remoteControl.undoButtonWasPushed(); } }
public class Test2 { public static void main(String[] args) { RemoteControl remoteControl = new RemoteControl(); //装置创建在合适的位置 Light livingRoomLight = new Light("Living Room"); Light kitchenLight = new Light("Kitchen"); 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); //创建音响的开与关命令 StereoOnWithCDCommand stereoOnWithCDCommand = new StereoOnWithCDCommand(stereo); StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo); //加载到遥控器插槽中去 remoteControl.setCommand(0,livingRoomLightOn,livingRoomLightOff); remoteControl.setCommand(1,kitchenLightOn,kitchenLightOff); remoteControl.setCommand(1,stereoOnWithCDCommand,stereoOffCommand); System.out.println(remoteControl); remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); remoteControl.onButtonWasPushed(1); remoteControl.offButtonWasPushed(1); remoteControl.onButtonWasPushed(2); remoteControl.offButtonWasPushed(2); } }
public class Stereo { public Stereo(String weizhi) { System.out.println("位置 = [" + weizhi + "]"); } public void on(){ System.out.println(".........打开dvd"); } public void off(){ System.out.println(".........关闭dvd");} public void setCd(){} public void setDvd(){} public void setRadio(){} public void setVolume(int num){System.out.println(".........调音量:"+num);} }