行爲型模式之命令模式


在軟件開發系統中,常常出現“方法的請求者”與“方法的實現者”之間存在緊密的耦合關係。這不利於軟件功能的擴展與維護。例如,想對行爲進行“撤銷、重做、記錄”等處理都很不方便,因此“如何將方法的請求者與方法的實現者解耦?”變得很重要,命令模式能很好地解決這個問題。

在現實生活中,這樣的例子也很多,例如,電視機遙控器(命令發送者)通過按鈕(具體命令)來遙控電視機(命令接收者),還有計算機鍵盤上的“功能鍵”等。

命令模式的定義

命令(Command)模式的定義如下:將一個請求封裝爲一個對象,使發出請求的責任和執行請求的責任分割開。這樣兩者之間通過命令對象進行溝通,這樣方便將命令對象進行儲存、傳遞、調用、增加與管理。

命令模式的結構

可以將系統中的相關操作抽象成命令,使調用者與實現者相關分離,其結構如下:
命令模式包含以下主要角色:
抽象命令類(Command)角色:聲明執行命令的接口,擁有執行命令的抽象方法 execute()。
具體命令角色(Concrete Command)角色:是抽象命令類的具體實現類,它擁有接收者對象,並通過調用接收者的功能來完成命令要執行的操作。
實現者/接收者(Receiver)角色:執行命令功能的相關操作,是具體命令對象業務的真正實現者。
調用者/請求者(Invoker)角色:是請求的發送者,它通常擁有很多的命令對象,並通過訪問命令對象來執行相關請求,它不直接訪問接收者。

命令模式的實現

/**
 * 實現者/接收者(`Receiver`):播放器
 */
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("暫停播放");}
}

/**
 * 抽象命令類(`Command`):播放器操作
 */
public interface IAction {
    void execute();
}
/**
 * 具體命令角色(`Concrete Command`):暫停播放
 */
public class PauseAction implements IAction {
    private GPlayer gplayer;
    public PauseAction(GPlayer gplayer) {this.gplayer = gplayer;}
    public void execute() {
    	gplayer.pause();//接受者執行暫停播放的功能
    }
}
/**
 * 具體命令角色(`Concrete Command`):正常播放
 */
public class PlayAction implements IAction {
    private GPlayer gplayer;
    public PlayAction(GPlayer gplayer) {this.gplayer = gplayer;}
    public void execute() {
        gplayer.play();
    }
}
/**
 * 具體命令角色(`Concrete Command`):拖動進度條
 */
public class SpeedAction implements IAction {
    private GPlayer gplayer;
    public SpeedAction(GPlayer gplayer) {this.gplayer = gplayer;}
    public void execute() {
        gplayer.speed();
    }
}
/**
 * 具體命令角色(`Concrete Command`):停止播放
 */
public class StopAction implements IAction {
    private GPlayer gplayer;
    public StopAction(GPlayer gplayer) {this.gplayer = gplayer;
    }
    public void execute() {
        gplayer.stop();
    }
}
/**
 * 調用者/請求者(`Invoker`):控制播放器,類似遙控器
 */
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) {
        System.out.println(">>>>>執行一個命令");
        GPlayer player = new GPlayer();
        Controller controller = new Controller();
        controller.execute(new PlayAction(player));
        System.out.println(">>>>>執行一組命令");
        controller.addAction(new PauseAction(player));
        controller.addAction(new PlayAction(player));
        controller.addAction(new StopAction(player));
        controller.addAction(new SpeedAction(player));
        controller.executes();
    }
}

程序運行結果如下:

>>>>>執行一個命令
正常播放
>>>>>執行一組命令
暫停播放
正常播放
停止播放
拖動進度條

命令模式的應用場景

命令模式通常適用於以下場景:
1.當系統需要將請求調用者與請求接收者解耦時,命令模式使得調用者和接收者不直接交互。
2.當系統需要隨機請求命令或經常增加或刪除命令時,命令模式比較方便實現這些功能。
3.當系統需要執行一組操作時,命令模式可以定義宏命令來實現該功能。
4.當系統需要支持命令的撤銷(Undo)操作和恢復(Redo)操作時,可以將命令對象存儲起來,採用備忘錄模式來實現。

命令模式的優缺點

命令模式的主要優點如下:
1.降低系統的耦合度,命令模式能將調用操作的對象與實現該操作的對象解耦。
2.增加或刪除命令非常方便。採用命令模式增加與刪除命令不會影響其他類,它滿足“開閉原則”,對擴展比較靈活。
3.可以實現宏命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即宏命令。
4.方便實現 Undo 和 Redo 操作。命令模式可以與後面介紹的備忘錄模式結合,實現命令的撤銷與恢復。

缺點是:可能產生大量具體命令類。因爲計對每一個具體操作都需要設計一個具體命令類,這將增加系統的複雜性。

<<上一篇;策略模式
>>下一篇:責任鏈模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章