设计模式之命令模式
命令模式是通过对方法调用的封装实现请求调用者和请求接收者的解耦。请求调用者不需要知道接收者是怎么样执行命令的,它只需要调用一个方法,接收者就会执行特定的命令。
命令模式的类图如下
Command接口
public interface Command { public void execute(); public void undo(); }
实现了Command接口的LightOnCommand类,相当于类图中的ConcreteCommand,此外还有LightOffCommand
通过这个类实现了命令(on)和命令对象(Light)的绑定.
public class LightOnCommand implements Command { Light light; public LightOnCommand(Light light) { this.light=light; } public void execute() { light.on(); } public void undo() { light.off(); } }
接收请求的Light类(相当于Receiver)
public class Light { public void on() { System.out.println("light is on!"); } public void off() { System.out.println("light is off!"); } }
调用请求的SimpleRemoteControl类(相当于Invoker)
public class SimpleRemoteControl { Command[] onCommands;//命令接口的引用,表示open Command[] offCommands;//命令接口的引用,表示off Command undoCommand; public SimpleRemoteControl() { onCommands=new Command[7]; offCommands=new Command[7]; for(int i=0;i<7;i++) { onCommands[i]=new NoCommand(); offCommands[i]=new NoCommand(); } undoCommand=new NoCommand(); } public void setCommand(int slot,Command onCommand,Command offCommand) { onCommands[slot]=onCommand; offCommands[slot]=offCommand; } //当on按钮按下时调用的方法 public void onButtonWasPressed(int slot) { onCommands[slot].execute(); undoCommand=onCommands[slot]; } //当off按钮按下时调用的方法 public void offButtonWasPressed(int slot) { offCommands[slot].execute(); undoCommand=offCommands[slot]; } public void undoButtonWasPressed() { System.out.println("undo!"); undoCommand.undo(); } }
测试类,相当于Client
public class Test { public static void main(String[] args) { SimpleRemoteControl remote=new SimpleRemoteControl(); Light light=new Light(); GarageDoor door=new GarageDoor(); LightOffCommand lightOffCommand=new LightOffCommand(light); //绑定light和关灯的命令 LightOnCommand lightOnCommand=new LightOnCommand(light); //绑定light和开灯的命令 GarageDoorCloseCommand closeDoor=new GarageDoorCloseCommand(door);//绑定door和关门的命令 GarageDoorOpenCommand openDoor=new GarageDoorOpenCommand(door);//绑定door和开门的命令 remote.setCommand(0,lightOnCommand,lightOffCommand); remote.setCommand(1,openDoor,closeDoor); remote.onButtonWasPressed(0); remote.onButtonWasPressed(1); remote.offButtonWasPressed(0); remote.offButtonWasPressed(1); remote.undoButtonWasPressed(); } }
运行结果
命令模式不仅可以实现运行(execute),还可以实现undo操作,如果需要回到最早的状态,可以使用一个栈来记住每次的操作,每次调用undo方法的时候就拿栈顶的元素进行undo。命令模式还可以实现宏命令的调用,例如上面例子中,可以将setCommand()的onCommand和offCommand改为数组,设置一系列的操作。
命令模式还可用在队列请求和日志请求。比如有一个工作队列,在一端添加命令,在另一端是线程,线程就每次取出一个命令,然后调用excute方法,等待调用完成,然后丢弃这个命令,再取下一个命令。再比如,我们对一个表格进行操作的时候,假如我们要保存这个表格之前的状态以便实现撤销,我们并不是保存整个表格,而是记录每次的操作到日志中,若数据丢失,则可以重新执行日志中的各种操作,把表格恢复到检查点的状态。