命令模式,將請求封裝成物件,這可以讓你使用不同的請求佇列或日誌請求來引數化物件,命令模式也可以支援撤銷操作. 當發出請求和執行請求的物件需要解耦時,使用命令物件.

我們來看一個例子:遙控器例子,我們想通過遙控器控制家中的各種電器;實現這樣的功

能要求:.

  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()方法呼叫命令;