1. 程式人生 > >設計模式 --- 命令模式

設計模式 --- 命令模式

1.定義

將一個請求封裝成一個物件,從而讓使用者使用不同的請求把客戶端引數化;對請求排隊或者記錄請求日誌,以及支援可撤銷的操作。

 

2.使用場景

需要抽象出待執行的動作,然後以引數的形式提供出來,類似於過程設計中的回撥機制。

在不同的時刻指定、排列和執行請求。

需要支援取消操作。

支援修改日誌功能。

需要支援事物操作。

 

3.簡單實現

以一個電視遙控器功能為例,遙控器能控制電視機的開機、關機、調解音量、切換頻道。

//定義一個接收者角色,真正具體處理邏輯的方法
class TvFunction{
    //執行開機
    void PowerOn(){
        System.out.println("底層呼叫硬體通電...開機");
    }
    //執行關機
    void PowerOff(){
        System.out.println("底層呼叫硬體斷電...關機");
    }
    //執行頻道切換
    void ChangeChannal(){
        System.out.println("呼叫底層程式程式碼...切換頻道");
    }
    //執行音量調節
    void TurnVoice(){
        System.out.println("呼叫底層程式程式碼...調節音量");
    }
}

interface Command{
    //命令執行的方法
    void execute();
}

//開機命令
class PowerOn implements Command{
    //持有一個接收者的引用
    private TvFunction function;

    public PowerOn(TvFunction function) {
        this.function = function;
    }

    @Override
    public void execute() {
        //呼叫具體的開機方法
        function.PowerOn();
    }
}

//關機命令
class PowerOFF implements Command{
    //持有一個接收者的引用
    private TvFunction function;

    public PowerOFF(TvFunction function) {
        this.function = function;
    }

    @Override
    public void execute() {
        //呼叫具體的關機機方法
        function.PowerOff();
    }
}

//頻道切換命令
class Channal implements Command{
    //持有一個接收者的引用
    private TvFunction function;

    public Channal(TvFunction function) {
        this.function = function;
    }

    @Override
    public void execute() {
        //呼叫具體的切換頻道方法
        function.ChangeChannal();
    }
}

//音量調節命令
class Voice implements Command{
    //持有一個接收者的引用
    private TvFunction function;

    public Voice(TvFunction function) {
        this.function = function;
    }

    @Override
    public void execute() {
        //呼叫具體的音量調節方法
        function.TurnVoice();
    }
}

//定義請求者 遙控器
class TvContorllor{
    private PowerOn powerOn; //開機物件的引用
    private PowerOFF powerOFF; //關機物件的引用
    private Channal channal;    //頻道切換物件的引用
    private Voice voice;    //音量調節物件的引用

    public void setPowerOn(PowerOn powerOn) {
        this.powerOn = powerOn;
    }

    public void setPowerOFF(PowerOFF powerOFF) {
        this.powerOFF = powerOFF;
    }

    public void setChannal(Channal channal) {
        this.channal = channal;
    }

    public void setVoice(Voice voice) {
        this.voice = voice;
    }

    //開機
    public void powerOn(){
        powerOn.execute();
    }

    //關機
    public void powerOff(){
        powerOFF.execute();
    }

    //調解音量
    public void turnVoice(){
        voice.execute();
    }

    //切換頻道
    public void changeChannal(){
        channal.execute();
    }
}

public class CommandMode {

    public static void main(String[] args){
        //首先要有電視機的功能
        TvFunction function = new TvFunction();

        //構造4種命令
        PowerOn powerOn = new PowerOn(function);
        PowerOFF powerOFF = new PowerOFF(function);
        Channal channal = new Channal(function);
        Voice voice = new Voice(function);

        //構造一個遙控器
        TvContorllor tvContorllor = new TvContorllor();
        tvContorllor.setPowerOn(powerOn);
        tvContorllor.setPowerOFF(powerOFF);
        tvContorllor.setChannal(channal);
        tvContorllor.setVoice(voice);

        //使用者可以隨便按遙控器控制電視
        tvContorllor.powerOn();
        tvContorllor.changeChannal();
        tvContorllor.turnVoice();
        tvContorllor.powerOff();
    }

輸出:

呼叫邏輯做的如此複雜,原因是為了程式碼交給別人來維護時,比較清晰,遵循了設計模式重要原則:對修改關閉對拓展開放。此外,還有一個好處是可以再TvContorllor類中儲存執行過的命令,我們可以方便知道執行過哪些命令,還可以恢復。

 

4.小結

優點:

更弱的耦合性,更靈活的控制性,更好的拓展性;

缺點:

類的膨脹,大量的衍生類