【設計模式】學習筆記8:命令模式(Command)

來源:互聯網
上載者:User

本文出自   http://blog.csdn.net/shuangde800

走進命令模式

在餐廳的情境中,我們看看餐廳是怎樣工作的:

1、顧客走進餐廳,點好菜後,產生訂單交給女服務員

2、女服務員訂單拿到廚房工作室,大喊一聲:“訂單來了!”

3、廚師訂單準備餐點。

上面情境各角色職責:

1、訂單封裝了顧客的請求。 和一般的對象一樣,訂單可以被傳遞,訂單內包含一個方法 orderUp(), 這個方法封裝了準備餐點所需的動作。訂單內有廚師的引用。這些都被封裝起來。

2、女服務員的工作就是接受訂單,然後調用訂單的orderUp( )方法。這裡的orderUp具體內容就是把訂單交給廚師。

       女服務員不必知道訂單的內容是什麼,只需要知道訂單中有一個orderUp( )的方法可以調用就夠了。

3、廚師具備準備餐點的知識

廚師是一種對象,他真正知道如何準備餐點。一旦女服務員調用orderUp( )方法,廚師就接手馬上做好餐點。

女服務員和廚師之間的關係是徹底解耦的,請注意,女服務員的訂單封裝了餐點的細節,她只要調用訂單的方法即可,而廚師看了訂單就知道該做什麼餐點,廚師和女服務員之間從來不用直接溝通。

從餐廳到命令模式


把餐廳想象成OO設計模式中的一種模型,這個模型允許將“發出的請求的對象”和“接受與執行這些請求的對象”分隔開來。


比方說,對於遙控器的例子:


有一個遙控器

上面有不同功能的卡槽,旁邊對應卡槽的開關按鈕,遙控器廠商提供了相關卡槽功能的類。如何設計這個遙控器的API?

對於遙控器API,我們需要分隔開“發出請求的的按鈕代碼”和執行請求的"廠商特定對象"。

假設遙控器插槽上有一個餐廳訂單的對象,那麼按按鈕,就會調用該對象的orderUp()方法,然後就可以等待大餐上來了!


命令模式可以將“動作的要求者”從動作的執行者對象中解耦。上面遙控器是要求者,而執行者對象就是廠商類的其中之一的執行個體。

利用命令模式把遙控器每個鍵的請求封裝成一個特定對象,所以,每個按鈕都儲存一個命令對象,那麼當按下按鈕時,就可以請命令對象做相關的工作。遙控器並不需要知道工作內容是什麼,只要有這個命令對象就能和正確的對象溝通,把事情做好就可以了。


第一個命令對象
下面用命令模式實現遙控器的代碼 1. 實現命令介面

// 命令介面,所有的命令對象實現這個介面public interface Command {    // 簡單! 只需要一個方法:execute()    public void execute();}

2. 實現一個開啟電燈的命令

// 實現一個開啟電燈的命令// 要實現Command的介面public class LightOnCommand implements Command{    Light light;    // light是接收者    public LightOnCommand(Light light) {        this.light = light;     }    // 執行接收者的動作    public void execute() {        light.on();     }}

3. 使用命令對象


下面是調用者

public class SimpleRemoteControl{    // 有一個插槽持有命令,而這個命令控制著一個裝置    Command slot;     public SimpleRemoteControl() { }    // 這個方法用來設定插槽控制的命令。    // 如果這段代碼的客戶想要改變    public void setCommand(Command command) {        slot = command;     }    // 當按下按鈕時,這個方法就會被調用    // 使得當前命令銜接插槽,並調用他的execute()方法    public void buttonWasPressed() {        slot.execute();    }}

4. 遙控器使用的簡單測試

下面代碼,用來測試上面的簡單遙控器

public class RemoteControlTest {//這是命令模式的客戶    public static void main(String[] args) {        // 遙控器就是調用者,會傳入一個命令對象,可以用來發出請求        SimpleRemoteControl remote = new SimpleRemoteControl();        // 建立一個電燈對象,此對象是接收者        Light light = new Light();        // 這裡建立一個命令,然後接收者傳給他        LightOnCommand lightOn = new LightOnCommand(light);        // 把命令傳給調用者        remote.setCommand(lightOn);        // 類比按下按鈕        remote.buttonWasPressed();    }}

定義命令模式

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


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


2.每一個命令都是一個操作:請求的一方發出請求,要求執行一個操作;接收的一方收到請求,並執行操作。


3.命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的介面,更不必知道請求是怎麼被接收,以及操作是否被執行、何時被執行,以及是怎麼被執行的。


4.命令模式使請求本身成為一個對象,這個對象和其他對象一樣可以被儲存和傳遞。


5.命令模式的關鍵在於引入了抽象命令介面,且寄件者針對抽象命令介面編程,只有實現了抽象命令介面的具體命令才能與接收者相關聯。

撤銷命令模式

要在遙控器加上撤銷功能很簡單,它的功能是這樣的:比如說是電燈關閉的,你按下了開啟按鈕,電燈就亮了,然後你按下撤銷按鈕,燈就又不亮了。相當與撤銷上一次的命令。

1. 在Command介面上加上undo()方法

public interface Command {    public void execute();    public void undo();}

2. 如果是開燈的命令,那麼他的撤銷命令就是關燈。同理,如果是關燈的命令,那麼他的撤銷命令就是開燈。

// 開燈命令public class LightOnCommand implements Command{    Light light;    public LightOnCommand(Light light) {        this.light = light;     }    public void execute() {        light.on();     }    // 實現了撤銷功能:變成關燈    public void undo(){        light.off();    }}

// 關燈命令public class LightOffCommand implements Command{    Light light;    public LightOffCommand(Light light) {        this.light = light;     }    public void execute() {        light.off();     }    // 關燈的撤銷命令是開燈    public void undo(){        light.on();    }}

要實現命令模式的撤銷功能,還是很簡單的,只要學會了儲存上一次的命令,那麼隨便就可以寫出來了

宏命令模式

如果遙控器擁有一個功能,按下一個按鈕,就可以實現很多功能,要怎麼做?

也很簡單,用一個數組存下所有命令即可

public class MacroCommand implements Command {    Command[] commands;    public MacroCommand(Command[] commands) {        this.commands = commands;     }    public void execute() {        for(int i = 0; i < commands.length; i++)            commands[i].execute();    }    public void undo() {        for(int i = 0; i < commands.length; ++i)            commands[i].undo();    }}


如果要可以撤銷很多次怎麼做?

也很簡單,不只是記錄最後一個被執行的命令,而使用一個堆棧記錄操作過程的沒一個命令。然後不管什麼時候按下了撤銷按鈕,你都可以從堆棧中取出最上層的命令,然後調用它的undo()方法。



命令模式的更多用途: 隊列請求

命令可以將運算塊打包,然後把它傳來傳去,就像是一般的對象一樣。即使命令對象被建立許久之後,運算依然可以被調用。

事實上,它甚至可以在不同的線程中被調用。我們利用這樣的特性衍生出一些應用,例如:排程(Scheduler),線程池,工作隊列等。




命令模式的更多用途:日誌請求

某些應用需要把所有動作都記錄在日誌中,並能在系統死機後,重新調用這些動作恢複到之前的狀態。

通過新增兩個方法(store(), load() ),命令模式就能夠支援這一點。

在只要當我們執行命令時,將記錄儲存在磁碟中,一旦系統死機,就可以將命令對象重載,並成批地一次調用這些

對象的execute()方法。





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.