1. 程式人生 > 實用技巧 >設計模式——命令模式

設計模式——命令模式

軟體開發中,通常會存在 “方法的請求者” 與 “方法的實現者” 之間存在緊密的耦合關係。這不利於軟體功能的擴充套件與維護。特別是針對行為進行(撤銷、重做、記錄)一系列操作時很不方便,因此 “如何將方法的請求者與方法的實現者解耦”,是命令模式的主要任務和功能。在現實生活中,這樣的例子也很多,例如,電視機遙控器(命令傳送者)通過按鈕(具體命令)來遙控電視機(命令接收者)

一、命令模式的基本介紹


1)、命令模式(Command Pattern):是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳遞給物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。
2)、命令模式使得請求傳送者與請求接受者消除彼此之間的耦合,讓物件之間的呼叫關係更加靈活,實現解耦。
3)、在命令模式中,會將一個請求封裝為一個物件,以便使用不同的引數(執行者)來表示不同的請求。同時命令模式也支援撤銷的操作。
4)、增加或刪除命令非常方便。採用命令模式增加和刪除命令不會影響其他類,它滿足 “開閉原則” ,即擴充套件靈活。
5)、可以實現巨集命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即巨集命令。
6)、方便實現 Undo 和 Redo 操作(適合命令模式)。命令模式可以與後面介紹的備忘錄模式結合,實現命令的撤銷與恢復。
7)、其缺點是:可能產生大量具體命令類。因為對每一個具體操作都需要設計一個具體命令類,這將增加系統的複雜性。

二、命令模式結構類圖


命令模式包含以下主要角色
【1】、介面命令(Command)角色:宣告執行命令的介面,擁有執行命令的抽象方法。
【2】、具體命令(Concrete Command)角色:是抽象命令類的具體實現類,它擁有接收者物件,並通過呼叫接收者的功能來完成命令要執行的操作。
【3】、接收者(Receiver)角色:執行命令功能的相關操作,是具體命令物件業務的真正實現者。
【4】、呼叫者(Invoker)角色:是請求的傳送者,它通常擁有很多的命令物件,並通過訪問命令物件來執行相關請求,不直接訪問接收者。

三、命令模式案例分析


我們通過寫一個空調遙控器按鈕的案例來體會命令模式的特點

【1】介面命令角色

:Command,其包含兩個主要方法(execute() 與 undo())

1 public interface Command {
2     //命令的執行方法
3     public void execute();
4     //撤銷操作
5     public void undo();
6 }

【2】具體命令實現類:寫一個制熱的命令類,實現命令介面,並組合接受者角色,呼叫目標方法。類似的類還有製冷等等。

 1 //制熱命令
 2 public class HeadCommand implements Command{
 3     //組合空調具體執行類
 4     private
AirCondition airCondition; 5 //構造器 6 public HeadCommand(AirCondition airCondition) { 7 super(); 8 this.airCondition = airCondition; 9 } 10 11 @Override 12 public void execute() { 13 //呼叫空調的制熱方法 14 airCondition.Head(); 15 } 16 17 @Override 18 public void undo() { 19 //返回上一次操作 20 airCondition.refrigeration(); 21 } 22 23 }

【3】接收者角色:空調類(AirCondition )

 1 //空調類
 2 public class AirCondition {
 3     //制熱
 4     public void Head() {
 5         System.out.println("空調製熱.......");
 6     }
 7     //製冷
 8     public void  refrigeration() {
 9         System.out.println("空調開始製冷......");
10     }
11 }

【4】呼叫者角色:遙控器類 (RemoteController )

 1 //呼叫者( 遙控器 ),也是命令模式的精華
 2 public class RemoteController {
 3     //新增命令按鈕
 4     Command[] commands;
 5     //撤銷按鈕
 6     Command undo;
 7     //構造器
 8     public RemoteController() {
 9         //初始化按鈕
10         commands = new Command[5];
11         for(int i=0;i<5;i++) {
12             commands[i] = new NoCommand();
13         }
14     }
15     
16     //給遙控器新增按鈕
17     public void setCommand(int n , Command command) {
18         commands[n]=command;
19     }
20     
21     //呼叫制熱按鈕
22     public void headCommonButton(int n) {
23         commands[n].execute();
24     }
25     
26     //撤回
27     public void undoButton() {
28         undo.undo();
29     }
30     
31 }

【5】客戶端呼叫

 1 public class Client {
 2     public static void main(String[] args) {
 3         //建立空調例項
 4         AirCondition airCondition = new AirCondition();
 5         //呼叫命令類
 6         RemoteController remoteController = new RemoteController(); 
 7         //將命令新增至遙控按鈕中
 8         HeadCommand headCommand = new HeadCommand(airCondition);
 9         remoteController.setCommand(0,headCommand);
10         //呼叫制熱功能
11         remoteController.headCommonButton(0);
12     }
13 }

注意命令模式的好處:當增加新產品時,只需要建立新產品類即可。無需修改命令類,符合開閉原則。例如我們增加一個冰箱的制熱功能。只需要新增冰箱實體類和制熱命令類,同時在客戶端將其新增至命令類中即可,無需修改命令類。