指令模式
将“請求”封裝成對象,以便使用不同的請求、隊列或者日志來參數化其他對象。指令模式也支援可撤銷的操作。指令模式通過這種封裝的方式實作将用戶端和接收端解耦。
類型:
行為型模式(類與類之間的行為型模式)
指令模式的幾個角色:
- 抽象指令接口Command:定義指令的接口,聲明執行的方法。
- 具體的指令對象ConcreteCommand:持有具體的接受者對象,完成具體的具體的指令。
- 接受者對象Receiver:接受者對象,真正執行指令的對象。
- 傳遞指令對象Invoker:持有指令對象,要求指令對象執行請求。
- 用戶端對象Client:建立具體指令的對象并且設定指令對象的接受者。
指令模式關系圖:
指令模式示例:
本例子是呼叫小愛同學幫你開燈的例子,你對小愛同學說:小愛同學幫我打開燈,然後小愛同學讓燈自己打開了。
抽象指令接口Command:
/**
* Create by zhaihongwei on 2018/3/30
* 抽象的指令接口,定義具體命名的接口
*/
public interface Command {
/**
* 執行命名的接口
*/
void execute();
}
具體的指令對象ConcreteCommand:(開燈指令,關燈指令)
/**
* Create by zhaihongwei on 2018/3/30
* 開燈指令
*/
public class LightOnCommand implements Command{
private Light light;
/**
* 建立開燈指令的時候,傳入具體的燈對象,由燈對象操作自己
* @param light
*/
public LightOnCommand(Light light) {
this.light = light;
}
@Override
/**
* 具體的燈對象調用自己的開燈方法
*/
public void execute() {
light.lightOn();
}
}
/**
* Create by zhaihongwei on 2018/3/30
* 關燈指令
*/
public class LightOffCommand implements Command{
private Light light;
/**
* 建立關燈指令的時候,傳入具體的燈對象,由燈對象操作自己
* @param light
*/
public LightOffCommand(Light light) {
this.light = light;
}
@Override
/**
* 具體的燈對象調用自己的關燈方法
*/
public void execute() {
light.lightOff();
}
}
傳遞指令對象Invoker:
/**
* Create by zhaihongwei on 2018/3/30
* 小愛同學
*/
public class XiaoAi {
private Command command;
/**
* 設定具體的指令
* @param command
*/
public void setCommand(Command command) {
this.command = command;
}
/**
* 執行指令
*/
public void doCommand() {
command.execute();
}
}
接受者對象Receiver:
/**
* Create by zhaihongwei on 2018/3/30
* 具體的電燈類
*/
public class Light {
/**
* 開燈方法
*/
public void lightOn() {
System.out.println("燈打開了!!");
}
/**
* 關燈方法
*/
public void lightOff() {
System.out.println("燈關上了!!");
}
}
用戶端對象:
/**
* Create by zhaihongwei on 2018/3/30
* 用戶端對象
*/
public class Client {
public static void main(String[] args) {
// 建立小愛同學
XiaoAi xiaoAi = new XiaoAi();
// 建立具體的等對象,相當于具體的指令接受者
Light light = new Light();
// 建立了開燈的指令,你就是指令的發起者
System.out.println("小愛同學幫我把燈開一下!");
LightOnCommand lightOnCommand = new LightOnCommand(light);
// 小愛同學接受到了你發出的指令,并執行指令
xiaoAi.setCommand(lightOnCommand);
xiaoAi.doCommand();
System.out.println("-------------------------------------------------");
System.out.println("小愛同學幫我關一下燈!");
LightOffCommand lightOffCommand = new LightOffCommand(light);
xiaoAi.setCommand(lightOffCommand);
xiaoAi.doCommand();
}
}
測試結果:
小愛同學幫我把燈開一下!
燈打開了!!
-------------------------------------------------
小愛同學幫我關一下燈!
燈關上了!!
總結:
上面的例子僅僅是實作單個指令的的指令模式,而指令模式是可以相當複雜的,就比如說,你讓小愛同學幫你打開燈,并且幫你打開電視,并且打開空調等等,這時候我們可以将多個指令存儲起來,然後一次性執行。
關于NoCommand的了解:
在沒有設定具體的指令的時候将指令存儲中的對象都設定成NoCommand的,這樣做可以避免空指針異常,具體作用展現可以閱讀《Head First》 。
關于宏指令的了解:
将多個指令存儲起來,發出執行宏指令請求的之後執行存儲的所有指令。
關于指令撤銷的了解:
在我們發出某個請求并執行之後,将指令的執行狀态進行儲存,如果我們想要回歸執行這個指令之前的狀态,我們就可以通過指令撤銷的方式回歸到之前的狀态。
指令模式的優缺點:
優點:
- 實作用戶端和接受者之間的解耦。
- 可以動态的添加新的指令。
- 隻需要調用同一個方法(doCommand方法)便可以實作不同的功能。
缺點:
- 實作一個具體的指令系統,可能要建立很多的具體指令對象。