定義
命令模式是一個高內聚的模式,其定義如下:
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。
命令模式的通用類圖爲:
在該類圖中,我們看到三個角色:
-
Receive接收者角色
該角色就是幹活的角色,命令傳遞到這裏被執行; -
Command命令角色
需要執行的所有命令都在這裏聲明; -
Invoker調用者角色
接收到命令,並執行命令。
命令模式比較簡單,但是在項目中非常頻繁地使用,因爲它的封裝性非常好,把請求方(Invoker)和執行方(Receiver)分開了,擴展性也有很好的保障,能用代碼比較簡單。
通用Receiver類
public abstract class Receiver {
// 抽象接收者, 定義每個接收者者必須完成的業務
public abstract void doSomething();
}
具體的Receiver類
public class ConcreteReceiver1 extends Receiver {
public void doSomething() {
// do something
}
}
public class ConcreteReceiver2 extends Receiver {
public void doSomething() {
// do something
}
}
接收者可以是N個,這要依賴業務的具體定義。命令角色是命令模式的核心,其抽象的命令代碼如下:
public abstract class Command {
// 每個命令類都必須有一個執行命令的方法
public abstract void execute();
}
根據環境的需求,具體的命令類也可以有N個,其實現類如下:
public class ConcreteCommand1 extends Command {
// 對哪個Receiver類進行命令處理
private Receiver receiver;
public ConcreteCommand1(Receiver receiver) {
this.receiver = receiver;
}
// 必須實現一個命令
public void execute() {
// do something...
// 業務處理
this.receiver.doSomething();
}
}
public class ConcreteCommand2 extends Command {
// 對哪個Receiver類進行命令處理
private Receiver receiver;
public ConcreteCommand2(Receiver receiver) {
this.receiver = receiver;
}
// 必須實現一個命令
public void execute() {
// do something...
// 業務處理
this.receiver.doSomething();
}
}
這裏定義了兩個具體的命令類,讀者可以在實際應用中擴展該命令類。在每個命令類中,通過構造函數定義了該命令是針對哪一個接收者發出的,定義一個命令接收的主體。
調用者Invoker類:
public class Invoker {
private Command command;
// 接受命令
public void setCommand(Command _command) {
this.command = _command;
}
// 執行命令
public void action() {
this.command.execute();
}
}
調用者就像是一個受氣包,不管什麼命令,都要接收、執行!
場景類如下:
public class Client {
public static void main(String[] args) {
// 首先聲明調用者Invoker
Invoker invoker = new Invoker();
// 定義接收者
Receiver receiver = new ConcreteReciver1();
// 定義一個發送給接收者的命令
Command command = new ConcreteCommand1(receiver);
// 把命令交給調用者執行
invoker.setCommand(command);
invoker.action();
}
}
優點
-
類間解耦
調用者角色與接收者角色之間沒有任何依賴關係,調用者實現功能時只須調用Command抽象類的execute方法就可以,不需要關心到底是哪個接收者執行; -
可擴展性
Command的子類可以非常容易擴展,而調用者Invoker和高層的模塊Client不產生嚴重的代碼耦合; -
命令模式結合 其他模式更優秀
命令模式可以結合責任鏈模式,實現命令族解析任務;結合模板方法模式,則可以減少Command子類的膨脹問題。
缺點
命令模式也是有缺點的,請看Command的子類:如果有N個命令,問題就出來了,Command的子類就可不是幾個,而是N個,這個類膨脹得非常大,這個就需要我們在項目中慎重考慮使用。
使用場景
只要你認爲是命令的地方就可以採用命令模式,例如,在GUI開發中,一個按鈕的點擊是一個命令,可以採用命令模式;模擬DOS命令的時候,當然也要採用命令模式;觸發——反饋機制的處理等;