設計模式讀書筆記-----命令模式


         在開發過程中,我可能會需要向某些對象發送一些請求,但是我們不知請求的具體接收者是誰,也不知道被請求的操作是那個,我們只知道在程序運行中指定具體的請求接收者即可。打個比方,電視遙控器,我們只需要知道按那個按鈕能夠打開電視、關閉電視和換台即可,並不需要知道是怎么開電視、關電視和換台的。對於這種情況,我們可以采用命令模式來進行設計。

         一、基本定義                                                                                                           

         命令模式將請求封裝成對象,以便使用不同的請求、隊列或者日志來參數化其他對象。命令模式支持可撤銷的操作。

         命令模式可以對發送者額接受者完全解耦,發送者也接收者之間並沒有直接的聯系,發送者只需要知道如何發送請求,不需要關心請求是如何完成了。這就是命令模式,命令模式將方法調用給封裝起來了。

 

         二、模式結構                                                                                                          

         從上圖可以看出命令模式包含如下幾個角色:

            Command: 抽象命令類

            ConcreteCommand: 具體命令類

            Invoker: 調用者

            Receiver: 接收者

            Client:客戶類

         命令模式的本質就在於將命令進行封裝,將發出命令的責任和執行命令的責任分開,是的發送者只需要知道如何發送命令即可,不需要命令是如何實現的,甚至命令執行是否成功都不需要理會。同時命令模式使得請求也變成了一個對象,它像其他對象一樣可以被存儲和傳遞。

 

         三、模式實現                                                                                                          

         這里以電視機為例。電視劇是請求的接受者,遙控器是請求的發送者,遙控器上有一些按鈕,不同的按鈕對應着不同的操作。在這里遙控器需要執行三個命令:打開電視機、關閉電視機、換台。

         UML圖:

         代碼的實現

         抽象命令類:Command.java

1 /**
2  * Command命令接口,為所有的命令聲明一個接口。所有的命令都應該實現它
3  */
4 public interface Command {
5     public void execute();
6 }

         電視機類:Television.java

 1 public class Television {
 2     public void open(){
 3         System.out.println("打開電視機......");
 4     }
 5     
 6     public void close(){
 7         System.out.println("關閉電視機......");        
 8     }
 9     
10     public void changeChannel(){
11         
12         System.out.println("切換電視頻道......");
13     }
14 }

         遙控器類:Controller.java

 1 public class Controller {
 2     private Command openTVCommand;
 3     private Command closeTVCommand;
 4     private Command changeChannelCommand;
 5     
 6     public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
 7         this.openTVCommand = openTvCommand;
 8         this.closeTVCommand = closeTvCommand;
 9         this.changeChannelCommand = changeChannelCommand;
10     }
11     
12     /**
13      * 打開電視劇
14      */
15     public void open(){
16         openTVCommand.execute();
17     }
18     
19     /**
20      * 關閉電視機
21      */
22     public void close(){
23         closeTVCommand.execute();
24     }
25     
26     /**
27      * 換頻道
28      */
29     public void change(){
30         
31         changeChannelCommand.execute();
32     }
33     
34 }

         遙控器的三個按鈕

 1 public class OpenTvCommand implements Command{
 2     private Television tv;
 3     
 4     public OpenTvCommand(){
 5         tv = new Television();
 6     }
 7     
 8     public void execute() {
 9         tv.open();
10     }
11 
12 }

 

 1 public class ChangeChannelCommand implements Command{
 2     private Television tv;
 3     
 4     public ChangeChannelCommand(){
 5         tv = new Television();
 6     }
 7     
 8     public void execute() {
 9         tv.changeChannel();
10     }
11 
12 }
 1 public class CloseTvCommand implements Command{
 2     private Television tv;
 3     
 4     public CloseTvCommand(){
 5         tv = new Television();
 6     }
 7     
 8     public void execute() {
 9         tv.close();
10     }
11     
12 }

         客戶端:Client.java

 1 public class Client {
 2         public static void main(String a[])
 3         {
 4             Command openCommand,closeCommand,changeCommand;
 5             
 6             openCommand = new OpenTvCommand();
 7             closeCommand = new CloseTvCommand();
 8             changeCommand = new ChangeChannelCommand();
 9             
10             Controller control = new Controller(openCommand,closeCommand,changeCommand);
11             
12             control.open();           //打開電視機
13             control.change();         //換頻道
14             control.close();          //關閉電視機
15         }
16 
17 }

         運行結果

 

         四、模式優缺點                                                                                                        

         優點

             1. 降低了系統耦合度

             2. 新的命令可以很容易添加到系統中去。

         缺點

             使用命令模式可能會導致某些系統有過多的具體命令類。

 

         五、模式使用場景                                                                                                

             1.系統需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互。

             2.系統需要在不同的時間指定請求、將請求排隊和執行請求。

             3.系統需要支持命令的撤銷(Undo)操作和恢復(Redo)操作。

             5.系統需要將一組操作組合在一起,即支持宏命令。

 

         六、模式擴展                                                                                                        

             1. 撤銷命令

             在電視遙控器中,我們還有這樣一個按鈕,那就是返回。用於切換到上面一個頻道中去。在命令模式中也支持撤銷操作,在這里我們只需要記錄上一個頻道,然后將上一個頻道傳入即可。

             在這里將Command進行一個簡單的修改:將execute()改為execute(int I );i表示頻道,用於進行頻道切換。

 1 /**
 2  * Command命令接口,為所有的命令聲明一個接口。所有的命令都應該實現它
 3  */
 4 public interface Command {
 5     /**
 6      * 為了方便切換頻道,這里使用參數i將頻道傳遞
 7      * @param i
 8      */
 9     public void execute(int i);
10 }

       然后在Controller中添加channelUndo()方法,用於進行頻道返回。並且需要進行一些簡單的修改。

 1 public class Controller {
 2     private Command openTVCommand;
 3     private Command closeTVCommand;
 4     private Command changeChannelCommand;
 5     
 6     public int nowChannel = 0;       //當前頻道
 7     public int priorChannel;     //前一個頻道,用於執行返回操作
 8     
 9     public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
10         this.openTVCommand = openTvCommand;
11         this.closeTVCommand = closeTvCommand;
12         this.changeChannelCommand = changeChannelCommand;
13     }
14     
15     /**
16      * 打開電視劇
17      */
18     public void open(){
19         openTVCommand.execute(0);
20     }
21     
22     /**
23      * 關閉電視機
24      */
25     public void close(){
26         closeTVCommand.execute(0);
27     }
28     
29     /**
30      * 換頻道:只在當前頻道遞增
31      */
32     public void change(){
33         priorChannel = nowChannel;            //換頻道前記錄當前頻道
34         nowChannel++;       //頻道+1
35         changeChannelCommand.execute(nowChannel);
36     }
37     
38     /**
39      * 頻道返回
40      */
41     public void ChannelUndo(){
42         changeChannelCommand.execute(priorChannel);          //將以前的頻道傳入
43         //當前頻道與前一個頻道進行互換
44         int tempChannel;
45         tempChannel = priorChannel;
46         priorChannel = nowChannel;
47         nowChannel = tempChannel;
48     }
49 }

             客戶端

 

 1 public class Client {
 2         public static void main(String a[])
 3         {
 4             Command openCommand,closeCommand,changeCommand;
 5             
 6             openCommand = new OpenTvCommand();
 7             closeCommand = new CloseTvCommand();
 8             changeCommand = new ChangeChannelCommand();
 9             
10             Controller control = new Controller(openCommand,closeCommand,changeCommand);
11             
12             control.open();           //打開電視機
13             control.change();         //換頻道
14             control.change();
15             control.ChannelUndo();
16             control.ChannelUndo();
17             control.ChannelUndo();
18             control.close();          //關閉電視機
19         }
20 
21 }

             運行結果。

 

         七、總結                                                                                                                 

             1. 命令模式的本質就是將命令對象進行封裝打包,將發出命令的責任和執行命令的責任進行割開。

             2. 命令模式中發送者只需要知道如何發送請求命令,無須關心命令執行具體過程。

             3. 在發送者和接收者兩者間是通過命令對象進行溝通的。請求命令本身就當做一個對象在兩者間進行傳遞,它封裝了接收者和一組動作。

             4. 命令模式支持撤銷。

             5. 命令模式隊列請求和日志請求。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM