java設計模式之命令模式

命令模式的定義:

  命令模式是對命令的封裝,每個命令都是一個操做:請求方發出請求要求執行一個操做;接收方收到請求,並執行操做。命令模式解耦了請求方shell

和接收方,請求方只需請求執行命令,不用關心命令怎麼被接收、怎樣操做以及是否被執行等。命令模式屬於行爲型設計模式。設計模式

  在軟件系統中,行爲請求者與行爲實現者一般是一種緊耦合關係,由於這樣的實現簡單明瞭。但緊耦合關係缺少擴展性,在某些場合中,須要對行爲架構

進行記錄、撤銷或者重作等處理時,只能修改源碼。而命令模式經過在請求與實現之間引入一個抽象命令接口。解耦了請求與實現,而且中間件是抽象的,測試

它由不一樣的子類實現,所以具備擴展性。因此,命令模式的本質是解耦命令請求與處理。this

命令模式的應用場景:

  • 現實語義中具有「命令」的操做(如命令菜單、shell命令等)。
  • 請求的調用者和接收者須要解耦,使得調用者和接收者不之間交互。
  • 須要抽象除等待執行的行爲,好比撤銷操做和恢復等操做。
  • 須要支持命令宏(即命令組合操做)。

命令模式的UML類圖:

 

 

 

 

 從上圖能夠看出,命令模式主要包含4個角色。spa

  • 接收者角色(Receiver):該類負責具體實施或執行一個請求。
  • 命令模式(ICommand):定義須要執行的全部命令行爲。
  • 具體命令角色(ConcreteCommand):該類內部維護一個Receiver在其execute()方法中調用Receiver的相關方法。
  • 請求者角色(Invoker):接收客戶端的命令,並執行命令。

  從命令模式的UML類圖中,能夠很清晰地看出,ICommand的出現就是做爲Receiver和Invoker的中間件,解耦了彼此。命令行

使用命令模式重構播放器控制條:

  假如咱們開發一個播放器,播放器播放功能、拖動進度條功能、中止播放功能、暫停功能,咱們在操做播發器的時候並不知道之間調用播放器設計

哪一個功能,而是經過一個控制傳達去傳遞指令給播放器內核,具體傳達什麼指令,會被封裝成一個個按鈕。那麼每一個按鈕就至關於一條命令的封裝。日誌

用控制條實現了用戶發送指令與播放器內核接收指令的解耦。下面來看代碼,首先建立播放器內核類:code

public class GPlayer {
    public void play() {
        System.out.println("正常播放");
    }

    public void speed() {
        System.out.println("拖動進度條");
    }

    public void stop() {
        System.out.println("中止播放");
    }

    public void pause() {
        System.out.println("暫停播放");
    }
}

建立命令接口:

public interface IAction {
    void execute();
}

建立播放指令類:

public class PlayAction implements IAction {
    private GPlayer gplayer;

    public PlayAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.play();
    }
}

建立暫停指令類:

public class PauseAction implements IAction {
    private GPlayer gplayer;

    public PauseAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.pause();
    }
}

建立拖動進度條類:

public class SpeedAction implements IAction {
    private GPlayer gplayer;

    public SpeedAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.speed();
    }
}

建立中止播放指令:

public class StopAction implements IAction {
    private GPlayer gplayer;

    public StopAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.stop();
    }
}

建立控制條controller類:

public class Controller {
    private List<IAction> actions = new ArrayList<IAction>();

    public void addAction(IAction action) {
        actions.add(action);
    }

    public void execute(IAction action) {
        action.execute();
    }

    public void executes() {
        for (IAction action : actions) {
            action.execute();
        }
        actions.clear();
    }
}

從上面代碼來看,控制條能夠執行單條命令,也能夠批量執行多條命令。下面看客戶端的測試代碼:

public class Test {
    public static void main(String[] args) {

        GPlayer player = new GPlayer();
        Controller controller = new Controller();
        controller.execute(new PlayAction(player));

        controller.addAction(new PauseAction(player));
        controller.addAction(new PlayAction(player));
        controller.addAction(new StopAction(player));
        controller.addAction(new SpeedAction(player));
        controller.executes();
    }
}

因爲控制條已經與播放器內核解耦了,之後若是想擴展新命令,只須要增長命令便可,控制條的結構無須改動。

命令模式的優勢:

  • 經過引入中間件(抽象接口),解耦了命令請求與實現。
  • 擴展性良好,能夠很容易地增長新命令。
  • 支持組合命令,支持命令隊列。
  • 能夠在現有命令的基礎上,增長額外功能,好比日誌記錄,結合裝飾器模式會更加靈活。

命令模式的缺點:

  • 具體命令類可能過多。
  • 命令模式的結果其實就是接收方的執行結果,可是爲了以命令的形式進行架構、解耦請求與實現,引入額外類型結構(引入請求方與抽象命令接口)。
  • 增長了理解上的困難。不過這也是設計模式的通病抽象必然會額外增長類的數量;代碼抽離確定比代碼聚合更難理解。
相關文章
相關標籤/搜索