設計模式 —— 命令模式(Command Pattern)
阿新 • • 發佈:2019-01-29
命令模式(Command Pattern)
概念:
概述:在軟體設計中,我們經常會遇到某些物件傳送請求,然後某些物件接受請求後執行,但傳送請求的物件可能並不知道接受請求的物件是誰,執行的是什麼動作。此時可通過 命令模式 來實現,讓傳送者和接受者完全的鬆耦合,這樣可大大增強程式的靈活性。
定義:命令模式 將“請求”封裝成物件,以便使用不同的請求,佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。
組成:
Client(客戶):負責建立一個具體的命令(Concrete Command)
Invoker(呼叫者):呼叫者持有一個命令物件,並在某個時刻呼叫命令物件的 execute() 方法。
Command(命令介面):包含命令物件的 execute() 方法和 undo() 方法。
ConcreteCommand(具體命令):實現命令介面。包括兩個操作,執行命令和撤銷命令。
Receiver(接收者):接受命令並執行。
例子:
現在比較火的小米手機,可以當作遙控器控制多種不同的家電,手機發送命令,不同的電器接收到後執行。
Command 類
public interface Command {
public void execute();
public void undo();
}
開燈命令
public class LightOnCommand implements Command {
private Light light;
LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
}
開電視命令
public class TVOnCommand implements Command {
private TV tv;
public TVOnCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.on();
}
public void undo() {
tv.off();
}
}
家用電器介面類
public interface HouseholdAppliances {
public void on();
public void off();
}
電視類
public class TV implements HouseholdAppliances {
public void on() {
System.out.println("the TV on");
}
public void off() {
System.out.println("the TV off");
}
}
電燈類
public class Light implements HouseholdAppliances{
public void on() {
System.out.println("the light on");
}
public void off() {
System.out.println("the light off");
}
}
手機控制器類
public class MiPhone {
ArrayList commands;
public MiPhone() {
commands = new ArrayList();
}
public void setCommand(Command command) {
commands.add(command);
}
public void onButtonWasPushed(int slot) {
((Command)commands.get(slot-1)).execute();
}
public static void main(String[] args) {
MiPhone miPhone = new MiPhone();
//建立電器
Light light = new Light();
TV tv = new TV();
//建立命令
LightOnCommand lightOnCommand = new LightOnCommand(light);
TVOnCommand tvOnCommand = new TVOnCommand(tv);
//給小米手機設定命令
//設定第一個按鈕為開燈
miPhone.setCommand(lightOnCommand);
//設定第二個按鈕為開電視
miPhone.setCommand(tvOnCommand);
//開燈
miPhone.onButtonWasPushed(1);
//開電視
miPhone.onButtonWasPushed(2);
}
}
執行結果:
適用場景
- 系統需要將請求呼叫者和請求接收者解耦,使得呼叫者和接收者不直接互動。
- 系統需要在不同的時間指定請求、將請求排隊(如:執行緒池+工作佇列)和執行請求。
- 系統需要支援命令的撤銷(Undo)操作和恢復(Redo)操作。
- 系統需要將一組操作組合在一起,即支援巨集命令。
優缺點:
優點:
- 降低系統的耦合度:Command模式將呼叫操作的物件與知道如何實現該操作的物件解耦。
- Command是頭等的物件。它們可像其他的物件一樣被操縱和擴充套件。
- 組合命令:你可將多個命令裝配成一個組合命令,即可以比較容易地設計一個命令佇列和巨集命令。一般說來,組合命令是Composite模式的一個例項。
- 增加新的Command很容易,因為這無需改變已有的類。
- 可以方便地實現對請求的Undo和Redo。
缺點:
- 使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。
更多用途:
- 巨集命令模式:命令模式 加 組合模式,我們可以將多個命令組合到一起來實現命令的批處理。
- 佇列請求:將命令排成一個佇列打包,一個個呼叫 execute 方法,如執行緒池的任務佇列,執行緒不關心任務佇列中是讀 IO 還是計算,只取出命令後執行,接著進行下一個。
- 日誌請求:某些應用需要我們將所有的動作記錄在日誌中,然後在系統宕機等情況出現時,重新呼叫這些動作恢復到之前的狀態。如資料庫事務。
完
參考:
《Head first 設計模式》