定義: 将“請求”封裝為對象,以便使用不同的請求,隊列或者日志來參數化其他對象。指令模式也支援可撤銷的操作
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方法。