有时候必须向某个对象提交请求,但是却并不知道关于被请求操作或请求的接收者的任何信息。
命令模式的关键是一个抽象的Command类或接口。这个Command抽象类(或接口)里面包含了一个执行命令的方法execute()。这个方法由具体Command去实现。
假设有一个遥控器,它有四个按钮,需要将其中的两个设计为灯(Light)的开、关,另外两个控制收音机(Video)的开、关。
在这个例子中遥控器物理上根本没有与等或者收音机接触(要不然也不叫“遥控器”了),以面向对象的思想去理解,遥控器作为控制器应该是一个类,所有控制的light和Video应该注册到这个控制其上面。然后是Light和Video,Light应该具有开或者关的表现效果(就是亮或者灭,可开、关是对应的,开-->亮,关-->灭),Video也类似。
接下来就是Command类组了,这个是命令模式的核心,它们都具有一个execute接口暴露给调用者,不同的具体Command如LightOnCommand应该具有一个所控制灯的引用(要不然不知道这个命令对应哪盏灯)。因此命令模式的代码如下:
首先是light和Video
//Light,这里直接写成了on和off。跟准确的应该是亮和灭
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class Light {
public void on(){
System.out.println("Light is on!");
}
public void off(){
System.out.println("Light is off");
}
}
//Video
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class Video {
public void on(){
System.out.println("Video is on ");
}
public void off(){
System.out.println("Video is off");
}
public void turnUp(){
System.out.println("Video turnUp!");
}
public void turnDown(){
System.out.println("Video turnDown!");
}
}
然后是它们对应的命令,先是一个超类Command(接口)
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public interface Command {
void execute();
}
接着是具体的Command
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class VideoOnCommand implements Command {
Video video;
public VideoOnCommand(Video video) {
this.video = video;
}
@Override
public void execute() {
video.on();
video.turnUp();
}
}
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class VideoOffCommand implements Command{
Video video;
public VideoOffCommand(Video video) {
this.video = video;
}
@Override
public void execute() {
video.turnDown();
video.off();
}
}
然后是遥控器,buttonOn()和buttonOff()对应了遥控器在物理意义上的按钮。
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class RemoteControl {
Command[] onCommands;
Command[] offCommands;
public RemoteControl() {
this.onCommands = new Command[2];
this.offCommands=new Command[2];
}
public void setCommand(int slot,Command onCommand,Command offCommand){
onCommands[slot-1]=onCommand;
offCommands[slot-1]=offCommand;
}
public void buttonOn(int slot){
onCommands[slot-1].execute();
}
public void buttonOff(int slot){
offCommands[slot-1].execute();
}
}
最后是测试代码:
package Command;
/**
* Created by sgzhang on 2015/8/14.
*/
public class RemoteControlTest {
public static void main(String[] args){
RemoteControl remoteControl=new RemoteControl();
Light light=new Light();
LightOnCommand lightOn=new LightOnCommand(light);
LightOffCommand lightOff=new LightOffCommand(light);
remoteControl.setCommand(1,lightOn,lightOff);
Video video=new Video();
VideoOnCommand videoOn=new VideoOnCommand(video);
VideoOffCommand videoOff=new VideoOffCommand(video);
remoteControl.setCommand(2,videoOn,videoOff);
remoteControl.buttonOff(1);
remoteControl.buttonOn(2);
}
}
输出
Light is off
Video is on
Video turnUp!
可以看到,经过对遥控器的一些配置之后, 最后两行实现了对Light和Video的控制。
命令模式适用:
1,抽象出执行的动作以参数化某对象;
2,在不同的时刻指定、排列、执行请求;
3,支持取消
4,支持日志。比如系统宕机后可根据日志中的操作记录,顺序执行命令,让系统恢复到备份的状态。