命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
下面我们利用一个场景来进行理解理解
场景:有一个遥控器,可以控制电灯、音响的开关,遥控器发出一个打开或关闭电灯或音响的请求,这个请求被我们封装成了命令对象。然后将命令对象传给接受者(即电灯或音响),接受者就可以执行命令了。
下面我们就来看看代码的实现。首先我们先创建几个装置类对象
//装置电灯 public class Light { public void on(){ System.out.println("Light ON"); } public void off(){ System.out.println("Light OFF"); } } //装置音响 public class Stereo { public void on(){ System.out.println("Stereo ON"); } public void off(){ System.out.println("Stereo OFF"); } public void setCD(){ System.out.println("Stereo set a CD"); } public void setVolume(){ System.out.println("Stereo set volume 11"); } }
接着我们创建一个命令对象的接口,并创建各种装置的具体命令
//创建一个命令对象的接口,所以命令都实现此接口 public interface Command { //只需一个方法 public void execute(); } //命令对象--开灯命令 public class LightOnCommand implements Command{ Light light; public LightOnCommand(Light light){ this.light = light; } @Override public void execute() { light.on(); } } //命令对象--关灯命令 public class LightOffCommand implements Command{ Light light; public LightOffCommand(Light light){ this.light = light; } @Override public void execute() { light.off(); } } //命令对象--打开音响命令 public class StereoOnCommand implements Command { Stereo stereo; public StereoOnCommand(Stereo stereo){ this.stereo = stereo; } @Override public void execute() { stereo.on(); stereo.setCD(); stereo.setVolume(); } } //命令对象--关闭音响命令 public class StereoOffCommand implements Command{ Stereo stereo; public StereoOffCommand(Stereo stereo){ this.stereo = stereo; } @Override public void execute() { stereo.off(); } }
当然,少不了遥控器对象了
//遥控器对象 public class RemoteControl { Command[] onCommands; Command[] offCommands; public RemoteControl(){ onCommands = new Command[2]; offCommands = new Command[2]; Command noCommand = new NoCommand(); for(int i=0; i<2; 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 class Test { public static void main(String[] args) { //创建一个遥控器 RemoteControl remoteControl = new RemoteControl(); //创建电灯、音响装置对象 Light light = new Light(); Stereo stereo = new Stereo(); //创建所有装置的命令对象 LightOnCommand lightOnCommand = new LightOnCommand(light); LightOffCommand lightOffCommand = new LightOffCommand(light); StereoOnCommand stereoOnCommand = new StereoOnCommand(stereo); StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo); //将所有命令对象加载到遥控器中 remoteControl.setCommand(0, lightOnCommand, lightOffCommand); remoteControl.setCommand(1, stereoOnCommand, stereoOffCommand); //下面进行开与关按钮测试 remoteControl.onButtonWasPushed(0); remoteControl.OffButtonWasPushed(0); System.out.println("------"); remoteControl.onButtonWasPushed(1); remoteControl.OffButtonWasPushed(1); } }
运行结果如下:
当然这里还没有撤销操作,其实撤销就是倒过来,我们现在稍微加下某些代码就可以实现了。
首先在Command接口中添加撤销操作方法undo
//创建一个命令对象的接口,所以命令都实现此接口 public interface Command { //只需一个方法 public void execute(); public void undo(); }
接者在LightOnCommand中实现这个方法,因为开灯反过来就是添加light.off()方法
@Override public void undo() { light.on(); }
同样道理,在其他命令对象中加入相应的undo。最后,我们在遥控器中加入一个撤销按钮
//撤销按钮遥控器对象 public class RemoteControlWithUndo { Command[] onCommands; Command[] offCommands; //撤销前一个命令对记录在这个对象中 Command undoCommand; public RemoteControlWithUndo(){ onCommands = new Command[2]; offCommands = new Command[2]; Command noCommand = new NoCommand(); for(int i=0; i<2; 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 class Test { public static void main(String[] args) { //创建一个遥控器 RemoteControlWithUndo remoteControl = new RemoteControlWithUndo(); //创建电灯、音响装置对象 Light light = new Light(); Stereo stereo = new Stereo(); //创建所有装置的命令对象 LightOnCommand lightOnCommand = new LightOnCommand(light); LightOffCommand lightOffCommand = new LightOffCommand(light); StereoOnCommand stereoOnCommand = new StereoOnCommand(stereo); StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo); //将所有命令对象加载到遥控器中 remoteControl.setCommand(0, lightOnCommand, lightOffCommand); remoteControl.setCommand(1, stereoOnCommand, stereoOffCommand); //下面进行开与关按钮测试 remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); System.out.println("---撤销关闭电灯---"); remoteControl.undoButtonWasPushed(); System.out.println(); remoteControl.onButtonWasPushed(1); System.out.println("---撤销打开音响---"); remoteControl.onButtonWasPushed(1); } }
运行结果如下:
好了,这就是一个简单的命令模式了,重点在于将“请求”封装成对象。然后将这对象进行传输。
下一节:适配器模式