Java設計模式(18)之命令模式
阿新 • • 發佈:2019-02-05
命令模式
將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。命令模式通過這種封裝的方式實現將客戶端和接收端解耦。
型別:
行為型模式(類與類之間的行為型模式)
命令模式的幾個角色:
- 抽象命令介面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方法)便可以實現不同的功能。
缺點:
- 實現一個具體的命令系統,可能要建立很多的具體命令物件。