命令模式——讓程序暢通執行

(《設計模式解析與實戰——何紅輝,關愛民》讀書筆記)

一、定義
將一個請求封裝成一個對象,從而讓用戶使用不同的請求把客戶端參數化;對請求排隊或者記錄請求日誌,以及支持可撤銷的操作。
比如說一鍵裝機,用戶只需要動一下鼠標,它就會執行下載,裝機等一系列過程。

二、使用場景
(1)需要抽象出待執行的動作,然後以參數的形式提出來——類似於過程設計中的回調機制,而命令模式正是回調機制的一個面向對象的替代品;
(2)在不同的時刻指定、排列和執行請求。一個命令對象可以有與初始請求無關的生存期;
(3)需要支持取消操作;
(4)支持修改日誌功能,這樣當系統崩潰時,這些修改可以被重做一遍;
(5)需要支持事物操作。

三、命令模式的通用模式代碼

/**
 * 接收者類:執行具體邏輯的角色
 */
public class Receiver {
    /**
     * 真正執行具體命令邏輯的方法
     */
    public void action() {
        System.out.println("執行具體操作");
    }
}
/**
 * 抽象命令接口:定義所有具體命令類的抽象接口
 */
public interface Command {
    /**
     * 執行具體操作的命令
     */
    void execute();
}
/**
 * 具體命令類:執行具體邏輯
 */
public class ConcreteCommand implements Command {

    private Receiver mReceiver;// 持有一個對接收者對象的應用

    public ConcreteCommand(Receiver receiver) {
        super();
        this.mReceiver = receiver;
    }

    @Override
    public void execute() {
        // 調用接收者的相關方法來執行具體邏輯
        mReceiver.action();
    }
}
/**
 * 請求者類:調用命令對象執行具體的請求
 */
public class Invoker {

    private Command mCommand; // 持有一個對相應命令對象的引用

    public Invoker(Command command) {
        super();
        this.mCommand = command;
    }

    public void action() {
        // 調用具體命令對象的相關方法,執行具體命令
        mCommand.execute();
    }
}
/**
 * 客戶類
 */
public class Client {
    public static void main(String[] args) {
        // 構造一個接收者對象
        Receiver receiver = new Receiver();

        // 根據接收者對象構造一個命令對象
        Command command = new ConcreteCommand(receiver);

        // 根據具體的對象構造一個命令對象
        Invoker invoker = new Invoker(command);

        // 執行請求方法
        invoker.action();
    }
}

運行結果:
這裏寫圖片描述

四、命令模式的簡單實現

/**
 * 接收者角色 俄羅斯方塊遊戲
 */
public class TetrisMachine {
    /**
     * 真正處理“向左”操作的邏輯代碼
     */
    public void toLeft() {
        System.out.println("向左");
    }

    /**
     * 真正處理“向右”操作的邏輯代碼
     */
    public void toright() {
        System.out.println("向右");
    }

    /**
     * 真正處理“快速落下”操作的邏輯代碼
     */
    public void fastToBottom() {
        System.out.println("快速落下");
    }

    /**
     * 真正處理“改變形狀”操作的邏輯代碼
     */
    public void transform() {
        System.out.println("改變形狀");
    }
}
/**
 * 命令者抽象 定義執行方法
 */
public interface Command {
    /**
     * 命令執行方法
     */
    void execute();
}
/**
 * 具體命令者 向左移的命令類
 */
public class LeftCommand implements Command {

    // 持有一個接收者俄羅斯方塊遊戲對象的引用
    private TetrisMachine mMachine;

    public LeftCommand(TetrisMachine machine) {
        super();
        this.mMachine = machine;
    }

    @Override
    public void execute() {
        // 調用遊戲機裏的具體方法執行操作
        mMachine.toLeft();
    }
}
/**
 * 具體命令者 向右移的命令類
 */
public class RightCommand implements Command {

    // 持有一個接收者俄羅斯方塊遊戲對象的引用
    private TetrisMachine mMachine;

    public RightCommand(TetrisMachine machine) {
        super();
        this.mMachine = machine;
    }

    @Override
    public void execute() {
        // 調用遊戲機裏的具體方法執行操作
        mMachine.toright();
    }
}
/**
 * 具體命令者 快速落下的命令類
 */
public class FallCommand implements Command {

    // 持有一個接收者俄羅斯方塊遊戲對象的引用
    private TetrisMachine mMachine;

    public FallCommand(TetrisMachine machine) {
        super();
        this.mMachine = machine;
    }

    @Override
    public void execute() {
        // 調用遊戲機裏的具體方法執行操作
        mMachine.fastToBottom();
    }
}
/**
 * 具體命令者 改變形狀的命令類
 */
public class TransformCommand implements Command {

    // 持有一個接收者俄羅斯方塊遊戲對象的引用
    private TetrisMachine mMachine;

    public TransformCommand(TetrisMachine machine) {
        super();
        this.mMachine = machine;
    }

    @Override
    public void execute() {
        // 調用遊戲機裏的具體方法執行操作
        mMachine.transform();
    }
}
/**
 * 請求者類 命令由按鈕發起
 */
public class Buttons {

    // 向左移動的命令對象引用
    private LeftCommand mLeftCommand;
    // 向右移動的命令對象引用
    private RightCommand mRightCommand;
    // 快速落下的命令對象引用
    private FallCommand mFallCommand;
    // 變換形狀的命令對象引用
    private TransformCommand mTransformCommand;

    /**
     * 設置向左移動的命令對象
     * 
     * @param leftCommand
     */
    public void setLeftCommand(LeftCommand leftCommand) {
        this.mLeftCommand = leftCommand;
    }

    /**
     * 設置向右移動的命令對象
     * 
     * @param rightCommand
     */
    public void setRightCommand(RightCommand rightCommand) {
        this.mRightCommand = rightCommand;
    }

    /**
     * 設置快速落下的命令對象
     * 
     * @param fallCommand
     */
    public void setFallCommand(FallCommand fallCommand) {
        this.mFallCommand = fallCommand;
    }

    /**
     * 設置變換形狀的命令對象
     * 
     * @param transformCommand
     */
    public void setTransformCommand(TransformCommand transformCommand) {
        this.mTransformCommand = transformCommand;
    }

    /**
     * 按下按鈕向左移動
     */
    public void toLeft() {
        mLeftCommand.execute();
    }

    /**
     * 按下按鈕向右移動
     */
    public void toright() {
        mRightCommand.execute();
    }

    /**
     * 按下按鈕快速落下
     */
    public void fastToBottom() {
        mFallCommand.execute();
    }

    /**
     * 按下按鈕變換形狀
     */
    public void transform() {
        mTransformCommand.execute();
    }
}
/**
 * 客戶類
 */
public class Player {
    public static void main(String[] args) {
        // 構造一個俄羅斯方塊遊戲
        TetrisMachine machine = new TetrisMachine();

        // 根據遊戲構造四種命令
        LeftCommand leftCommand = new LeftCommand(machine);
        RightCommand rightCommand = new RightCommand(machine);
        FallCommand fallCommand = new FallCommand(machine);
        TransformCommand transformCommand = new TransformCommand(machine);

        // 按鈕可以執行不同的命令
        Buttons buttons = new Buttons();
        buttons.setLeftCommand(leftCommand);
        buttons.setRightCommand(rightCommand);
        buttons.setFallCommand(fallCommand);
        buttons.setTransformCommand(transformCommand);

        // 具體按下哪個按鈕玩家說了算
        buttons.toLeft();
        buttons.toright();
        buttons.fastToBottom();
        buttons.transform();
    }
}

運行結果:
這裏寫圖片描述

大部分開發者或許使用一下代碼:

// 構造一個俄羅斯方塊遊戲
TetrisMachine machine = new TetrisMachine();

machine.toLeft();
machine.toright();
machine.fastToBottom();
machine.transform();

同樣可以得到期望的結果,而且代碼也少,邏輯簡單,但是對於開發者來說是方便,如果有一天開發者不再負責這個項目,這樣的邏輯留給後來者,就不會有人覺得方便了,而且設計模式有一條原則:對修改關閉,對擴展開放。
而且命令模式另一個好處是可以實現命令記錄的功能,並可以在需要時恢復。

五、總結
優點:
(1)弱耦合性;
(2)靈活的控制性;
(3)更好的擴展形。
缺點:
類的膨脹,大量衍生類的創建。

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