设计模式之命令模式
1. 什么是命令模式
Command模式也叫命令模式 ,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
应用场景
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
- 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
- 调用前后需要对调用参数进行某些处理。
- 调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
命令模式的结构
- Command:Command抽象类。
- ConcreteCommand:Command的具体实现类。
- Receiver:需要被调用的目标对象。
- Invorker:通过Invorker执行Command对象。
2. 具体实例
这里以一个家电自动化遥控器API项目的问题为例来实现命令模式的应用。
其实遥控器的需求就是不同的按钮控制不同的家电,比如有控制灯的,有控制电视的,有控制音箱的。按照面向对象的设计原则,我们就设计家电类和控制类就可以实现了,控制类去控制家电类中不同的具体的命令。但是这种方案的缺陷是什么呢?就是我们要添加新的家电的时候需要添加新的类并且同时修改控制类,也就是说这个过程中不同的家电执行的命令和家电之间是高耦合的,不利于代码的维护和扩展。
既然命令是需要改变的变量,我们把命令单独抽取出来形成接口,然后有具体的类去实现它,这样的话其实就是把命令和家电之间的关系进行了解耦合。具体的设计方案如下:
看一下代码的具体实现:
Command接口:
public interface Command {
public void execute();
public void undo();
}
具体实现Command接口的类:
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light)
{
this.light=light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.On();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.Off();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light)
{
this.light=light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.Off();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.On();
}
}
等等。。。其余的设别的控制命令的实现类同理。
Control接口:
public interface Control {
public void onButton(int slot);
public void offButton(int slot);
public void undoButton();
}
实现类:
public class CommandModeControl implements Control{
private Command[] onCommands;
private Command[] offCommands;
private Stack<Command> stack=new Stack<Command>();
public CommandModeControl()
{
onCommands=new Command[5];
offCommands=new Command[5];
Command noCommand=new NoCommand();
for(int i=0,len=onCommands.length;i<len;i++)
{
onCommands[i]=noCommand;
offCommands[i]=noCommand;
}
}
public void setCommand(int slot,Command onCommand,Command offCommand)
{
onCommands[slot]=onCommand;
offCommands[slot]=offCommand;
}
@Override
public void onButton(int slot) {
onCommands[slot].execute();
stack.push(onCommands[slot]);
}
@Override
public void offButton(int slot) {
offCommands[slot].execute();
stack.push(offCommands[slot]);
}
@Override
public void undoButton() {
// TODO Auto-generated method stub
stack.pop().undo();
}
}
设备的类就不在赘述了,其实很简单的
最后是测试这个工程的类
public class ControlTest {
public static void main(String[] args) {
CommandModeControl control = new CommandModeControl();
MarcoCommand onmarco,offmarco;
Light bedroomlight = new Light("BedRoom");
Light kitchlight = new Light("Kitch");
Stereo stereo = new Stereo();
LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);
Command[] oncommands={bedroomlighton,kitchlighton};
Command[] offcommands={bedroomlightoff,kitchlightoff};
onmarco=new MarcoCommand(oncommands);
offmarco=new MarcoCommand(offcommands);
StereoOnCommand stereoOn = new StereoOnCommand(stereo);
StereoOffCommand stereoOff = new StereoOffCommand(stereo);
StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);
control.setCommand(0, bedroomlighton, bedroomlightoff);
control.setCommand(1, kitchlighton, kitchlightoff);
control.setCommand(2, stereoOn, stereoOff);
control.setCommand(3, stereoaddvol, stereosubvol);
control.setCommand(4, onmarco, offmarco);
control.onButton(0);
control.undoButton();
//control.offButton(0);
control.onButton(1);
control.offButton(1);
control.onButton(2);
control.onButton(3);
control.offButton(3);
control.undoButton();
control.offButton(2);
control.undoButton();
control.onButton(4);
control.offButton(4);
}
}
通过上面的命令模式的例子我们可以看到通过命令模式实现了命令与设备之间的解耦合,就是使得命令和设备之间不是那么强相关的,便不再是具体的设备中来写具体的命令,而是专门抽象出一个接口,然后由具体的命令去具体的实现它。