1. 定義
指令模式是一個高内聚的模式,其定義為:Encapsulate a request as an object , thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.(将一個請求封裝成一個對象,進而讓你使用不同的請求把用戶端參數化,對請求排隊或者記錄請求日志,可以提供指令的撤銷和恢複功能。)
2. 通用類圖
在該類圖中,我們看到三個角色:
- Receiver接受者角色
該角色就是幹活的角色,指令傳遞到這裡是應該被執行的,具體到我們上面的例子中就是Group的三個實作類。
- Command指令角色
需要執行的所有指令都在這裡聲明
- Invoker調用者角色
接收到指令,并執行指令。
3. 代碼實作
指令模式比較簡單,但是在項目中非常頻繁地使用,因為它的封裝性非常好,把請求方(Invoker)和執行方(Receiver)分開了,擴充性也有很好的保障,通用代碼比較簡單。
通用Receiver類
package CommandPattern;
public abstract class Receiver {
//抽象接受者,定義每個接受者都必須完成的業務
public abstract void doSomething();
}
很奇怪,為什麼Receiver是一個抽象類?那是因為接受者可以有多個,有多個就需要定義一個所有特性的抽象集合-抽象的接受者,其具體的接受者如下所示:
package CommandPattern;
public class ConcreteReceiver1 extends Receiver{
//每個接受者都必須處理一定的業務邏輯
public void doSomething()
{
}
}
package CommandPattern;
public class ConcreteReceiver2 extends Receiver{
//每個接受者都必須處理一定的業務邏輯
public void doSomething()
{
}
}
接受者可以有N個,這要依賴業務的具體含義。指令角色是指令模式的核心,其抽象的指令類如下一樣:
package CommandPattern;
public abstract class Command {
//每個指令類都必須有一個執行指令的方法
public abstract void execute();
}
根據環境的需求,具體的指令類也可以有N個,其實作類如下所示:
package CommandPattern;
public class ConcreteCommand1 extends Command{
//對哪個Receiver類進行指令處理
private Receiver receiver;
//構造函數傳遞接受者
public ConcreteCommand1(Receiver _receiver)
{
this.receiver=_receiver;
}
//必須實作一個指令
public void execute()
{
this.receiver.doSomething();
}
}
package CommandPattern;
public class ConcreteCommand2 extends Command{
//對哪個Receiver類進行指令處理
private Receiver receiver;
//構造函數傳遞接受者
public ConcreteCommand2(Receiver _receiver)
{
this.receiver=_receiver;
}
//必須實作一個指令
public void execute()
{
this.receiver.doSomething();
}
}
定義了兩個具體的指令類,讀者可以在實際應用中擴充該指令類。在每個指令類中,通過構造函數定義了該指令是針對哪一個接受者發出的,定義一個指令接收的主體。調用者非常簡單,僅實作指令的傳遞。
調用者Invoker類
package CommandPattern;
public class Invoker {
private Command command;
//接收包,接收指令
public void setCommand(Command _command) {
this.command = _command;
}
//接收指令
public void action()
{
this.command.execute();
}
}
調用者就像受氣包,不管什麼指令,都要接收、執行。下面的代碼時調用指令模式。
package CommandPattern;
public class Client {
public static void main(String[] agrs)
{
//首先聲明調用者Invoker
Invoker invoker=new Invoker();
//定義接收者
Receiver receiver=new ConcreteReceiver1();
//定義一個發給接收者的指令
Command command=new ConcreteCommand1(receiver);
//把指令交給調用者去執行
invoker.setCommand(command);
invoker.action();
}
}
3. 指令模式的應用
3.1 指令模式的優點:
- 類間解耦
調用者角色與接受者角色之間沒有任何依賴關系,調用者實作功能時隻需要調用Command抽象類的execute方法就可以,不需要了解到底是哪個接收者執行的;
- 可擴充性
Command的子類非常容易擴充,而調用者Invoker和高層次的子產品Client不産生嚴重的代碼耦合
- 指令模式結合其他模式會更優秀
指令模式可以結合責任鍊模式,實作指令族解析任務;結合模闆方法模式,則可以減少Command子類的膨脹問題。
3.2 指令模式的缺點
指令模式也是有缺點的,請看Command子類:如果有N個指令,問題就出來了,Command的子類可不是幾個,而是N個,這個類膨脹得非常大,這個就需要慎重考慮了。
3.3 指令模式的使用場景
隻要你認為是指令的地方就可以使用指令模式。例如,在GUI的開發中,一個按鈕點選是一個指令,可以采用指令模式;模拟DOS指令的時候,當然也要采用指令模式;觸發-回報機制的處理等。
4. 指令模式的擴充
反悔問題,有兩種方法可以解決:一是結合備忘錄模式還原最後狀态,該方法适合接受者為狀态的變更情況,而不适合事件處理;而是通過增加一個新的指令,實作事件的復原。