一、
1.因为是操作经常变化,所以封装操作为command对象。You can do that by introducing “command objects” into your design. A command object encapsulates a request to do something (like turn on a light) on a specific object (say, the living room light object). So, if we store a command object for each button, when the button is pressed we ask the command object to do some work. The remote doesn’t have any idea what the work is, it just has a command object that knows how to talk to the right object to get the work done.So, you see, the remote is decoupled from the light object!
2.The Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects
with different requests, queue or log requests, and support undoable operations.
3.When you need to decouple an object making requests from the objects that know how to perform the requests, use
the Command Pattern.
3.
4.
5.
6.
7.
8.
二、简单命令模式
1.
package headfirst.designpatterns.command.simpleremote; public interface Command { public void execute(); }
2.
1 package headfirst.designpatterns.command.simpleremote; 2 3 public class LightOnCommand implements Command { 4 Light light; 5 6 public LightOnCommand(Light light) { 7 this.light = light; 8 } 9 10 public void execute() { 11 light.on(); 12 } 13 }
3.
1 package headfirst.designpatterns.command.simpleremote; 2 3 public class Light { 4 5 public Light() { 6 } 7 8 public void on() { 9 System.out.println("Light is on"); 10 } 11 12 public void off() { 13 System.out.println("Light is off"); 14 } 15 }
4.
1 package headfirst.designpatterns.command.simpleremote; 2 3 // 4 // This is the invoker 5 // 6 public class SimpleRemoteControl { 7 Command slot; 8 9 public SimpleRemoteControl() {} 10 11 public void setCommand(Command command) { 12 slot = command; 13 } 14 15 public void buttonWasPressed() { 16 slot.execute(); 17 } 18 }
5.
1 package headfirst.designpatterns.command.simpleremote; 2 3 public class RemoteControlTest { 4 public static void main(String[] args) { 5 SimpleRemoteControl remote = new SimpleRemoteControl(); 6 Light light = new Light(); 7 GarageDoor garageDoor = new GarageDoor(); 8 LightOnCommand lightOn = new LightOnCommand(light); 9 GarageDoorOpenCommand garageOpen = 10 new GarageDoorOpenCommand(garageDoor); 11 12 remote.setCommand(lightOn); 13 remote.buttonWasPressed(); 14 remote.setCommand(garageOpen); 15 remote.buttonWasPressed(); 16 } 17 18 }
三、远程调用命令模式
1.
1 package headfirst.designpatterns.command.remote; 2 3 public class RemoteLoader { 4 5 public static void main(String[] args) { 6 RemoteControl remoteControl = new RemoteControl(); 7 8 Light livingRoomLight = new Light("Living Room"); 9 Light kitchenLight = new Light("Kitchen"); 10 CeilingFan ceilingFan= new CeilingFan("Living Room"); 11 GarageDoor garageDoor = new GarageDoor(""); 12 Stereo stereo = new Stereo("Living Room"); 13 14 LightOnCommand livingRoomLightOn = 15 new LightOnCommand(livingRoomLight); 16 LightOffCommand livingRoomLightOff = 17 new LightOffCommand(livingRoomLight); 18 LightOnCommand kitchenLightOn = 19 new LightOnCommand(kitchenLight); 20 LightOffCommand kitchenLightOff = 21 new LightOffCommand(kitchenLight); 22 23 CeilingFanOnCommand ceilingFanOn = 24 new CeilingFanOnCommand(ceilingFan); 25 CeilingFanOffCommand ceilingFanOff = 26 new CeilingFanOffCommand(ceilingFan); 27 28 GarageDoorUpCommand garageDoorUp = 29 new GarageDoorUpCommand(garageDoor); 30 GarageDoorDownCommand garageDoorDown = 31 new GarageDoorDownCommand(garageDoor); 32 33 StereoOnWithCDCommand stereoOnWithCD = 34 new StereoOnWithCDCommand(stereo); 35 StereoOffCommand stereoOff = 36 new StereoOffCommand(stereo); 37 38 remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); 39 remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff); 40 remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff); 41 remoteControl.setCommand(3, stereoOnWithCD, stereoOff); 42 43 System.out.println(remoteControl); 44 45 remoteControl.onButtonWasPushed(0); 46 remoteControl.offButtonWasPushed(0); 47 remoteControl.onButtonWasPushed(1); 48 remoteControl.offButtonWasPushed(1); 49 remoteControl.onButtonWasPushed(2); 50 remoteControl.offButtonWasPushed(2); 51 remoteControl.onButtonWasPushed(3); 52 remoteControl.offButtonWasPushed(3); 53 } 54 }
2.
1 package headfirst.designpatterns.command.remote; 2 3 // 4 // This is the invoker 5 // 6 public class RemoteControl { 7 Command[] onCommands; 8 Command[] offCommands; 9 10 public RemoteControl() { 11 onCommands = new Command[7]; 12 offCommands = new Command[7]; 13 14 Command noCommand = new NoCommand(); 15 for (int i = 0; i < 7; i++) { 16 onCommands[i] = noCommand; 17 offCommands[i] = noCommand; 18 } 19 } 20 21 public void setCommand(int slot, Command onCommand, Command offCommand) { 22 onCommands[slot] = onCommand; 23 offCommands[slot] = offCommand; 24 } 25 26 public void onButtonWasPushed(int slot) { 27 onCommands[slot].execute(); 28 } 29 30 public void offButtonWasPushed(int slot) { 31 offCommands[slot].execute(); 32 } 33 34 public String toString() { 35 StringBuffer stringBuff = new StringBuffer(); 36 stringBuff.append(" ------ Remote Control ------- "); 37 for (int i = 0; i < onCommands.length; i++) { 38 stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() 39 + " " + offCommands[i].getClass().getName() + " "); 40 } 41 return stringBuff.toString(); 42 } 43 }
3.
1 package headfirst.designpatterns.command.remote; 2 3 public class Stereo { 4 String location; 5 6 public Stereo(String location) { 7 this.location = location; 8 } 9 10 public void on() { 11 System.out.println(location + " stereo is on"); 12 } 13 14 public void off() { 15 System.out.println(location + " stereo is off"); 16 } 17 18 public void setCD() { 19 System.out.println(location + " stereo is set for CD input"); 20 } 21 22 public void setDVD() { 23 System.out.println(location + " stereo is set for DVD input"); 24 } 25 26 public void setRadio() { 27 System.out.println(location + " stereo is set for Radio"); 28 } 29 30 public void setVolume(int volume) { 31 // code to set the volume 32 // valid range: 1-11 (after all 11 is better than 10, right?) 33 System.out.println(location + " Stereo volume set to " + volume); 34 } 35 }
4.
1 package headfirst.designpatterns.command.remote; 2 3 public class StereoOnWithCDCommand implements Command { 4 Stereo stereo; 5 6 public StereoOnWithCDCommand(Stereo stereo) { 7 this.stereo = stereo; 8 } 9 10 public void execute() { 11 stereo.on(); 12 stereo.setCD(); 13 stereo.setVolume(11); 14 } 15 }
5.
四、有undo功能的命令模式
1.
1 package headfirst.designpatterns.command.undo; 2 3 public class RemoteLoader { 4 5 public static void main(String[] args) { 6 RemoteControlWithUndo remoteControl = new RemoteControlWithUndo(); 7 8 Light livingRoomLight = new Light("Living Room"); 9 10 LightOnCommand livingRoomLightOn = 11 new LightOnCommand(livingRoomLight); 12 LightOffCommand livingRoomLightOff = 13 new LightOffCommand(livingRoomLight); 14 15 remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); 16 17 remoteControl.onButtonWasPushed(0); 18 remoteControl.offButtonWasPushed(0); 19 System.out.println(remoteControl); 20 remoteControl.undoButtonWasPushed(); 21 remoteControl.offButtonWasPushed(0); 22 remoteControl.onButtonWasPushed(0); 23 System.out.println(remoteControl); 24 remoteControl.undoButtonWasPushed(); 25 26 CeilingFan ceilingFan = new CeilingFan("Living Room"); 27 28 CeilingFanMediumCommand ceilingFanMedium = 29 new CeilingFanMediumCommand(ceilingFan); 30 CeilingFanHighCommand ceilingFanHigh = 31 new CeilingFanHighCommand(ceilingFan); 32 CeilingFanOffCommand ceilingFanOff = 33 new CeilingFanOffCommand(ceilingFan); 34 35 remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff); 36 remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff); 37 38 remoteControl.onButtonWasPushed(0); 39 remoteControl.offButtonWasPushed(0); 40 System.out.println(remoteControl); 41 remoteControl.undoButtonWasPushed(); 42 43 remoteControl.onButtonWasPushed(1); 44 System.out.println(remoteControl); 45 remoteControl.undoButtonWasPushed(); 46 } 47 }
2.
1 package headfirst.designpatterns.command.undo; 2 3 // 4 // This is the invoker 5 // 6 public class RemoteControlWithUndo { 7 Command[] onCommands; 8 Command[] offCommands; 9 Command undoCommand; 10 11 public RemoteControlWithUndo() { 12 onCommands = new Command[7]; 13 offCommands = new Command[7]; 14 15 Command noCommand = new NoCommand(); 16 for(int i=0;i<7;i++) { 17 onCommands[i] = noCommand; 18 offCommands[i] = noCommand; 19 } 20 undoCommand = noCommand; 21 } 22 23 public void setCommand(int slot, Command onCommand, Command offCommand) { 24 onCommands[slot] = onCommand; 25 offCommands[slot] = offCommand; 26 } 27 28 public void onButtonWasPushed(int slot) { 29 onCommands[slot].execute(); 30 undoCommand = onCommands[slot]; 31 } 32 33 public void offButtonWasPushed(int slot) { 34 offCommands[slot].execute(); 35 undoCommand = offCommands[slot]; 36 } 37 38 public void undoButtonWasPushed() { 39 undoCommand.undo(); 40 } 41 42 public String toString() { 43 StringBuffer stringBuff = new StringBuffer(); 44 stringBuff.append(" ------ Remote Control ------- "); 45 for (int i = 0; i < onCommands.length; i++) { 46 stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() 47 + " " + offCommands[i].getClass().getName() + " "); 48 } 49 stringBuff.append("[undo] " + undoCommand.getClass().getName() + " "); 50 return stringBuff.toString(); 51 } 52 }
3.
1 package headfirst.designpatterns.command.undo; 2 3 public class NoCommand implements Command { 4 public void execute() { } 5 public void undo() { } 6 }
4.
1 package headfirst.designpatterns.command.undo; 2 3 public class Light { 4 String location; 5 int level; 6 7 public Light(String location) { 8 this.location = location; 9 } 10 11 public void on() { 12 level = 100; 13 System.out.println("Light is on"); 14 } 15 16 public void off() { 17 level = 0; 18 System.out.println("Light is off"); 19 } 20 21 public void dim(int level) { 22 this.level = level; 23 if (level == 0) { 24 off(); 25 } 26 else { 27 System.out.println("Light is dimmed to " + level + "%"); 28 } 29 } 30 31 public int getLevel() { 32 return level; 33 } 34 }
5.
package headfirst.designpatterns.command.undo; public class LightOffCommand implements Command { Light light; int level; public LightOffCommand(Light light) { this.light = light; } public void execute() { level = light.getLevel(); light.off(); } public void undo() { light.dim(level); } }
6.
1 package headfirst.designpatterns.command.undo; 2 3 public class LightOnCommand implements Command { 4 Light light; 5 int level; 6 public LightOnCommand(Light light) { 7 this.light = light; 8 } 9 10 public void execute() { 11 level = light.getLevel(); 12 light.on(); 13 } 14 15 public void undo() { 16 light.dim(level); 17 } 18 }
7.
1 package headfirst.designpatterns.command.undo; 2 3 public class CeilingFan { 4 public static final int HIGH = 3; 5 public static final int MEDIUM = 2; 6 public static final int LOW = 1; 7 public static final int OFF = 0; 8 String location; 9 int speed; 10 11 public CeilingFan(String location) { 12 this.location = location; 13 speed = OFF; 14 } 15 16 public void high() { 17 speed = HIGH; 18 System.out.println(location + " ceiling fan is on high"); 19 } 20 21 public void medium() { 22 speed = MEDIUM; 23 System.out.println(location + " ceiling fan is on medium"); 24 } 25 26 public void low() { 27 speed = LOW; 28 System.out.println(location + " ceiling fan is on low"); 29 } 30 31 public void off() { 32 speed = OFF; 33 System.out.println(location + " ceiling fan is off"); 34 } 35 36 public int getSpeed() { 37 return speed; 38 } 39 }
8.
1 package headfirst.designpatterns.command.undo; 2 3 public class CeilingFanHighCommand implements Command { 4 CeilingFan ceilingFan; 5 int prevSpeed; 6 7 public CeilingFanHighCommand(CeilingFan ceilingFan) { 8 this.ceilingFan = ceilingFan; 9 } 10 11 public void execute() { 12 prevSpeed = ceilingFan.getSpeed(); 13 ceilingFan.high(); 14 } 15 16 public void undo() { 17 if (prevSpeed == CeilingFan.HIGH) { 18 ceilingFan.high(); 19 } else if (prevSpeed == CeilingFan.MEDIUM) { 20 ceilingFan.medium(); 21 } else if (prevSpeed == CeilingFan.LOW) { 22 ceilingFan.low(); 23 } else if (prevSpeed == CeilingFan.OFF) { 24 ceilingFan.off(); 25 } 26 } 27 }
9.
1 package headfirst.designpatterns.command.undo; 2 3 public class CeilingFanLowCommand implements Command { 4 CeilingFan ceilingFan; 5 int prevSpeed; 6 7 public CeilingFanLowCommand(CeilingFan ceilingFan) { 8 this.ceilingFan = ceilingFan; 9 } 10 11 public void execute() { 12 prevSpeed = ceilingFan.getSpeed(); 13 ceilingFan.low(); 14 } 15 16 public void undo() { 17 if (prevSpeed == CeilingFan.HIGH) { 18 ceilingFan.high(); 19 } else if (prevSpeed == CeilingFan.MEDIUM) { 20 ceilingFan.medium(); 21 } else if (prevSpeed == CeilingFan.LOW) { 22 ceilingFan.low(); 23 } else if (prevSpeed == CeilingFan.OFF) { 24 ceilingFan.off(); 25 } 26 } 27 }
五、全部关或开
1.
1 package headfirst.designpatterns.command.party; 2 3 public class RemoteLoader { 4 5 public static void main(String[] args) { 6 7 RemoteControl remoteControl = new RemoteControl(); 8 9 Light light = new Light("Living Room"); 10 TV tv = new TV("Living Room"); 11 Stereo stereo = new Stereo("Living Room"); 12 Hottub hottub = new Hottub(); 13 14 LightOnCommand lightOn = new LightOnCommand(light); 15 StereoOnCommand stereoOn = new StereoOnCommand(stereo); 16 TVOnCommand tvOn = new TVOnCommand(tv); 17 HottubOnCommand hottubOn = new HottubOnCommand(hottub); 18 LightOffCommand lightOff = new LightOffCommand(light); 19 StereoOffCommand stereoOff = new StereoOffCommand(stereo); 20 TVOffCommand tvOff = new TVOffCommand(tv); 21 HottubOffCommand hottubOff = new HottubOffCommand(hottub); 22 23 Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn}; 24 Command[] partyOff = { lightOff, stereoOff, tvOff, hottubOff}; 25 26 MacroCommand partyOnMacro = new MacroCommand(partyOn); 27 MacroCommand partyOffMacro = new MacroCommand(partyOff); 28 29 remoteControl.setCommand(0, partyOnMacro, partyOffMacro); 30 31 System.out.println(remoteControl); 32 System.out.println("--- Pushing Macro On---"); 33 remoteControl.onButtonWasPushed(0); 34 System.out.println("--- Pushing Macro Off---"); 35 remoteControl.offButtonWasPushed(0); 36 } 37 }
2.
1 package headfirst.designpatterns.command.party; 2 3 public class MacroCommand implements Command { 4 Command[] commands; 5 6 public MacroCommand(Command[] commands) { 7 this.commands = commands; 8 } 9 10 public void execute() { 11 for (int i = 0; i < commands.length; i++) { 12 commands[i].execute(); 13 } 14 } 15 16 /** 17 * NOTE: these commands have to be done backwards to ensure 18 * proper undo functionality 19 */ 20 public void undo() { 21 for (int i = commands.length -1; i >= 0; i--) { 22 commands[i].undo(); 23 } 24 } 25 }
3.
1 package headfirst.designpatterns.command.party; 2 3 // 4 // This is the invoker 5 // 6 public class RemoteControl { 7 Command[] onCommands; 8 Command[] offCommands; 9 Command undoCommand; 10 11 public RemoteControl() { 12 onCommands = new Command[7]; 13 offCommands = new Command[7]; 14 15 Command noCommand = new NoCommand(); 16 for(int i=0;i<7;i++) { 17 onCommands[i] = noCommand; 18 offCommands[i] = noCommand; 19 } 20 undoCommand = noCommand; 21 } 22 23 public void setCommand(int slot, Command onCommand, Command offCommand) { 24 onCommands[slot] = onCommand; 25 offCommands[slot] = offCommand; 26 } 27 28 public void onButtonWasPushed(int slot) { 29 onCommands[slot].execute(); 30 undoCommand = onCommands[slot]; 31 } 32 33 public void offButtonWasPushed(int slot) { 34 offCommands[slot].execute(); 35 undoCommand = offCommands[slot]; 36 } 37 38 public void undoButtonWasPushed() { 39 undoCommand.undo(); 40 } 41 42 public String toString() { 43 StringBuffer stringBuff = new StringBuffer(); 44 stringBuff.append(" ------ Remote Control ------- "); 45 for (int i = 0; i < onCommands.length; i++) { 46 stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() 47 + " " + offCommands[i].getClass().getName() + " "); 48 } 49 stringBuff.append("[undo] " + undoCommand.getClass().getName() + " "); 50 return stringBuff.toString(); 51 } 52 }
4.
1 package headfirst.designpatterns.command.party; 2 3 public class CeilingFanHighCommand implements Command { 4 CeilingFan ceilingFan; 5 int prevSpeed; 6 7 public CeilingFanHighCommand(CeilingFan ceilingFan) { 8 this.ceilingFan = ceilingFan; 9 } 10 public void execute() { 11 prevSpeed = ceilingFan.getSpeed(); 12 ceilingFan.high(); 13 } 14 public void undo() { 15 switch (prevSpeed) { 16 case CeilingFan.HIGH: ceilingFan.high(); break; 17 case CeilingFan.MEDIUM: ceilingFan.medium(); break; 18 case CeilingFan.LOW: ceilingFan.low(); break; 19 default: ceilingFan.off(); break; 20 } 21 } 22 }
六、命令模式的其他作用
1.queuing requests
2.logging requests