定义: 将“请求”封装为对象,以便使用不同的请求,队列或者日志来参数化其他对象。命令模式也支持可撤销的操作
UML类图
Command:为所有的命令声明了一个接口,调用命令对象的execute方法即可让接收者进行相关动作。
ConcreteCommand:定义了动作和接收者之间的绑定关系,调用者只需要调用其execute方法即可发出请求,然后由ConcreteCommand调用接收者的动作。
Receiver:接受者知道如何进行必要的工作,实现这个请求,任何类都可作为接收者。
Invoker:调用者持有一个Command引用,调用其execute方法发出请求。
分析: 命令对象将动作和接收者包进对象中,只暴露出一个execute方法,当该方法被调用时,接收者就会进行这些动作,从外面看,其他对象并不知道究竟哪个接收者进行了哪些动作。
示例
有一个具有7个插槽的遥控器,每个插槽可以制定到不同的家电上,都有开和关按钮,还有一个整体的撤销功能。
接收者
public class Door {
private String name;
public Door(String name) {
this.name = name;
}
public void on(){
System.out.println(name+":打开门");
}
public void off(){
System.out.println(name+":关上门");
}
}
public class Light {
private String name;
public Light(String name) {
this.name = name;
}
public void on(){
System.out.println(name+":灯开了");
}
public void off(){
System.out.println(name+":灯关了");
}
}
public class Stereo {
private String name;
public Stereo(String name) {
this.name = name;
}
public void off(){
System.out.println(name+":CD机关闭");
}
public void on(){
System.out.println(name+":CD机打开");
}
public void setCD(){
System.out.println("CD已插入");
}
public void setVolumn(int volumn){
System.out.println("设置音量为:"+volumn);
}
}
命令接口
public interface Command {
void execute();
}
具体命令类
public class GarageDoorCloseCommand implements Command {
private Door door;
public GarageDoorCloseCommand(Door door) {
this.door = door;
}
@Override
public void execute() {
door.off();
}
}
public class GarageDoorOpenCommand implements Command {
private Door door;
public GarageDoorOpenCommand(Door door) {
this.door = door;
}
@Override
public void execute() {
door.on();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
public class NoCommand implements Command {
@Override
public void execute() {
System.out.println("初始化");
}
}
public class StereoOffCommand implements Command {
private Stereo stereo;
public StereoOffCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.off();
}
}
public class StereoOnCommand implements Command {
private Stereo stereo;
public StereoOnCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.on();
stereo.setCD();
stereo.setVolumn(11);
}
}
调用者
public class RemoteControl {
private Command[] onCommands;
private Command[] offCommands;
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
NoCommand 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();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\n---------遥控器----------\n");
for(int i = 0;i < onCommands.length;i++){
stringBuilder.append("[卡槽"+i+"]"+onCommands[i].getClass().getName()+" "+"[卡槽"+i+"]"+offCommands[i].getClass().getName()+"\n");
}
return stringBuilder.toString();
}
}
测试
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light livingLight = new Light("卧室灯");
Light kitchenLight = new Light("厨房灯");
Door garageDoor = new Door("车库门");
Stereo stereo = new Stereo("欣欣");
LightOnCommand livingLightOnCommand = new LightOnCommand(livingLight);
LightOnCommand kitchenLightOnCommand = new LightOnCommand(kitchenLight);
LightOffCommand livingLightOffCommand = new LightOffCommand(livingLight);
LightOffCommand kitchenLightOffCommand = new LightOffCommand(kitchenLight);
GarageDoorOpenCommand garageDoorOpenCommand = new GarageDoorOpenCommand(garageDoor);
GarageDoorCloseCommand garageDoorCloseCommand = new GarageDoorCloseCommand(garageDoor);
StereoOnCommand stereoOnCommand = new StereoOnCommand(stereo);
StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
remoteControl.setCommand(0,livingLightOnCommand,livingLightOffCommand);
remoteControl.setCommand(1,kitchenLightOnCommand,kitchenLightOffCommand);
remoteControl.setCommand(2,garageDoorOpenCommand,garageDoorCloseCommand);
remoteControl.setCommand(3,stereoOnCommand,stereoOffCommand);
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);
}
}
更多用途
1、队列请求:实现命令接口的对象被放入队列中,线程从队列中提取命令对象,并将其从队列中删除,调用其execute方法,完成动作,再去处理下一个命令对象。工作队列对象并不在乎到底做些什么工作,它们只是取出命令对象,调用execute方法。
2、日志请求:通过在命令对象中添加store和load两个方法,每调用一次execute,命令对象被store到磁盘上,如果系统出状况,我们从本地中调用load方法,按次序批量执行命令对象的execute方法。