《一天一模式》— 命令模式

1、命令模式的概念

將「請求」封裝成對象,以便使用不一樣的請求、隊列或者日誌來參數化其餘對象。命令模式也支持可撤銷的操做。 java

2、何時使用命令模式

調用者與實現者一般是一種緊耦合的關係,但某些場合,好比須要對行爲進行記錄、撤銷或重作、事務等處理時,這種沒法抵禦變化的緊耦合的設計就不太合適。 我一般這麼理解命令模式,某些業務場景,一族對象會有一組命令,以命令的角度爲主定義命令對象(有執行和撤回兩種操做),而後把執行的過程委託給對象。this

什麼是一族對象?舉個例子,就是奔馳汽車、寶馬汽車、奧迪汽車等。spa

什麼是一組命令?舉個例子,就是遠程控制汽車時的開門命令、開空調命令、開天窗命令等。線程

這種狀況就可使用命令模式。使用命令模式有下降耦合、可擴展、可讀性高、使用方便(可撤回)等等的好處。設計

具體咱們來看一下,如何用Java代碼實現命令模式。日誌

3、怎麼使用命令模式

3.1 實現方式

仍是以上面的需求爲例子,使用命令模式對上面的業務進行實現,下面是類圖和代碼:code

代碼以下:對象

// 車輛抽象類
public abstract class Vehicle {

    abstract void openDoor();

    abstract void openWindow();

}

public class Audi extends Vehicle {

    void openDoor() {
        System.out.println("奧迪:開門。");
    }

    void openWindow() {
        System.out.println("奧迪:開窗。");
    }

}

public class Benz extends Vehicle {

    void openDoor() {
        System.out.println("奔馳:開門。");
    }

    void openWindow() {
        System.out.println("奔馳:開窗。");
    }

}

// 命令模式接口
public interface Command {

    void execute();

}

// 開門命令
public class OpenDoorCommand implements Command {

    private Vehicle vehicle;

    public OpenDoorCommand(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    public void execute() {
        vehicle.openDoor();
    }

}

// 開窗命令
public class OpenWindowCommand implements Command {

    private Vehicle vehicle;

    public OpenWindowCommand(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    public void execute() {
        vehicle.openWindow();
    }

}

public class Client {

    public static void main(String[] args) {
        // 建立開門命令
        Command openDoorCommand = new OpenDoorCommand(new Benz());
        // 建立開窗命令
        Command openWindowCommand = new OpenWindowCommand(new Audi());
        // 執行2個命令
        openDoorCommand.execute();
        openWindowCommand.execute();
    }

}

//輸出:
//奔馳:開門。
//奧迪:開窗。

3.2 命令模式的好處

使用命令的模式的好處以下:blog

  • 可讀性高:從語義上可直接閱讀到動做,對外提供了統一的表現;
  • 拓展性高:能夠很方便地添加新的命令,也能夠控制命令的撤回或重複執行;
  • 耦合性低:解除了調用者與具體實現的耦合, 屏蔽了底層的複雜實現;

3.3 注意事項

功能足夠簡單。若是功能自己比較簡單,則不建議引入命令模式,它會帶來更多的複雜性,以及更高的開發成本。接口

命令的意義不清晰或常常變化時,則不太適合使用命令模式。

通常來講,儘可能設計傻瓜式命令,它只懂得調用一個接收者的一個行爲(單一職責)。

4、總結

如何實現撤銷命令,是一直值得討論的問題,面相擴展性來講,能夠遵循一個設計方式:

不要只是記錄最後一個命令,而使用一個堆棧(後進先出)記錄操做過的每個命令。而後,無論何時執行撤銷,你均可以從堆棧中取出最上層的命令,而後執行undo()方法來撤銷它。

最後說一些其餘的,命令模式還能夠有更多的用途,好比使用在隊列請求和日誌請求。

想象一下,有一個工做隊列(先進先出),你在某一端添加命令,而後另外一端則是線程,線程從隊列中取出一個命令,而後調用它的execute()方法,等待這個調用完成,而後丟棄該命令,執行下一個……

在想象一下,某些應用須要咱們將全部的動做都記錄在日誌中,並能在系統死機後,從新調用這些動做恢復到以前的狀態。咱們能夠在執行命令的時候,將歷史記錄存儲在磁盤中。一旦系統死機重啓後,咱們就能夠將命令對象讀取出來從新執行execute()方法。

以上就是我對命令模式的一些理解,有不足之處請你們指出,謝謝。

相關文章
相關標籤/搜索