命令模式,將請求封裝成物件,這可以讓你使用不同的請求佇列或日誌請求來引數化物件,命令模式也可以支援撤銷操作. 當發出請求和執行請求的物件需要解耦時,使用命令物件.
我們來看一個例子:遙控器例子,我們想通過遙控器控制家中的各種電器;實現這樣的功
能要求:.
1 各種電器提供控制命令介面;
2 遙控器物件
3 遙控器上各個插槽對應的命令,命令物件,
4 各種電器
定義命令介面:
public interface Command {
public void execute();
}
各種電器物件,我們將各種電器物件單獨定義並將物件命令封裝進來.也就是各種電器物件的命令方法;
public class Light {
public Light() {
}
public void on() {
System.out.println(“Light is on”);
}
public void off() {
System.out.println(“Light is off”);
}
}
定義各種電器各種命令的物件實現COMMAND的介面;對應遙控器的各個操作;
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
}
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
}
定義遙控器物件;
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();
remote.setCommand(lightOff);
remote.buttonWasPressed();
}
}
遙控器不需要命令到底是如何執行的,只需要在呼叫的時候呼叫就可以;命令都是動態傳入的。實現了請求者和執行者的完全解耦,通過命令介面把兩部分連線起來。
空物件應用:
public class NoCommand implements Command {
public void execute() { }
}
在初始化命令時,比如遙控器中可能某個插槽無對應命令,我們可以為空,返回空物件;這個物件什麼都不做,這種方式被常用,也可以作為設計模式的一種。
我們重新實現遙控器(有些電器物件程式碼這裡沒給出,可以去51CTO下載。
public class RemoteControl {
Command[] onCommands;
Command[] offCommands;
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;
}
}
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(”
—— Remote Control ——-
“);
for (int i = 0; i < onCommands.length; i++) {
stringBuff.append(“[slot ” + i + “] ” + onCommands[i].getClass().getName()
+ “ ” + offCommands[i].getClass().getName() + ”
“);
}
return stringBuff.toString();
}
}
測試類:
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);
StereoOffCommand stereoOff =
new StereoOffCommand(stereo);
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);
remoteControl.setCommand(3, 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);
}
}
命令模式具有撤銷機制:
public interface Command {
public void execute();
public void undo();
}
命令介面增加撤銷方法;
ublic class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
public void undo() {
light.on();
}
相應的電器命令實現撤銷命令;
遙控器類增加記錄撤銷命令的屬性;
public class RemoteControlWithUndo {
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteControlWithUndo() {
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;
}
public void setCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
public void undoButtonWasPushed() {
undoCommand.undo();
}
public String toString() {
StringBuffer stringBuff = new StringBuffer();
stringBuff.append(”
—— Remote Control ——-
“);
for (int i = 0; i < onCommands.length; i++) {
stringBuff.append(“[slot ” + i + “] ” + onCommands[i].getClass().getName()
+ “ ” + offCommands[i].getClass().getName() + ”
“);
}
stringBuff.append(“[undo] ” + undoCommand.getClass().getName() + ”
“);
return stringBuff.toString();
}
}
此外,也可以定義巨集命令,一次執行一組命令;與事務機制相似;
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 = 0; i < commands.length; i++) {
commands[i].undo();
}
}
}
這時實現一個簡單定義巨集;
在測試中實現如下:
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light light = new Light(“Living Room”);
TV tv = new TV(“Living Room”);
Stereo stereo = new Stereo(“Living Room”);
Hottub hottub = new Hottub();
LightOnCommand lightOn = new LightOnCommand(light);
StereoOnCommand stereoOn = new StereoOnCommand(stereo);
TVOnCommand tvOn = new TVOnCommand(tv);
HottubOnCommand hottubOn = new HottubOnCommand(hottub);
LightOffCommand lightOff = new LightOffCommand(light);
StereoOffCommand stereoOff = new StereoOffCommand(stereo);
TVOffCommand tvOff = new TVOffCommand(tv);
HottubOffCommand hottubOff = new HottubOffCommand(hottub);
Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn};
Command[] partyOff = { lightOff, stereoOff, tvOff, hottubOff};
MacroCommand partyOnMacro = new MacroCommand(partyOn);
MacroCommand partyOffMacro = new MacroCommand(partyOff);
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);
}
}
呼叫者可以通過呼叫命令物件的EXCUTE()方法呼叫命令;