1. 程式人生 > >Java設計模式(18)之命令模式

Java設計模式(18)之命令模式

命令模式

將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。命令模式通過這種封裝的方式實現將客戶端和接收端解耦。

型別:

行為型模式(類與類之間的行為型模式)

命令模式的幾個角色:

  • 抽象命令介面Command:定義命令的介面,宣告執行的方法。
  • 具體的命令物件ConcreteCommand:持有具體的接受者物件,完成具體的具體的命令。
  • 接受者物件Receiver:接受者物件,真正執行命令的物件。
  • 傳遞命令物件Invoker:持有命令物件,要求命令物件執行請求。
  • 客戶端物件Client:建立具體命令的物件並且設定命令物件的接受者。

命令模式關係圖:

這裡寫圖片描述

命令模式示例:

本例子是呼叫小愛同學幫你開燈的例子,你對小愛同學說:小愛同學幫我開啟燈,然後小愛同學讓燈自己打開了。

抽象命令介面Command:

/**
 * Create by zhaihongwei on 2018/3/30
 * 抽象的命令介面,定義具體命名的介面
 */
public interface Command {

    /**
     * 執行命名的介面
     */
    void execute();
}

具體的命令物件ConcreteCommand:(開燈命令,關燈命令)

/**
 * Create by zhaihongwei on 2018/3/30
 * 開燈命令
 */
public class LightOnCommand implements Command{ private Light light; /** * 建立開燈命令的時候,傳入具體的燈物件,由燈物件操作自己 * @param light */ public LightOnCommand(Light light) { this.light = light; } @Override /** * 具體的燈物件呼叫自己的開燈方法 */ public void execute() { light.lightOn(); } }
/**
 * Create by zhaihongwei on 2018/3/30
 * 關燈命令
 */
public class LightOffCommand implements Command{

    private Light light;

    /**
     * 建立關燈命令的時候,傳入具體的燈物件,由燈物件操作自己
     * @param light
     */
    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    /**
     * 具體的燈物件呼叫自己的關燈方法
     */
    public void execute() {
        light.lightOff();
    }
}

傳遞命令物件Invoker:

/**
 * Create by zhaihongwei on 2018/3/30
 * 小愛同學
 */
public class XiaoAi {

    private Command command;

    /**
     * 設定具體的命令
     * @param command
     */
    public void setCommand(Command command) {
        this.command = command;
    }

    /**
     * 執行命令
     */
    public void doCommand() {
        command.execute();
    }
}

接受者物件Receiver:

/**
 * Create by zhaihongwei on 2018/3/30
 * 具體的電燈類
 */
public class Light {

    /**
     * 開燈方法
     */
    public void lightOn() {
        System.out.println("燈打開了!!");
    }

    /**
     * 關燈方法
     */
    public void lightOff() {
        System.out.println("燈關上了!!");
    }
}

客戶端物件:

/**
 * Create by zhaihongwei on 2018/3/30
 * 客戶端物件
 */
public class Client {

    public static void main(String[] args) {
        // 建立小愛同學
        XiaoAi xiaoAi = new XiaoAi();
        // 建立具體的等物件,相當於具體的命令接受者
        Light light = new Light();
        // 建立了開燈的命令,你就是命令的發起者
        System.out.println("小愛同學幫我把燈開一下!");
        LightOnCommand lightOnCommand = new LightOnCommand(light);
        // 小愛同學接受到了你發出的命令,並執行命令
        xiaoAi.setCommand(lightOnCommand);
        xiaoAi.doCommand();

        System.out.println("-------------------------------------------------");
        System.out.println("小愛同學幫我關一下燈!");
        LightOffCommand lightOffCommand = new LightOffCommand(light);
        xiaoAi.setCommand(lightOffCommand);
        xiaoAi.doCommand();

    }
}

測試結果:

小愛同學幫我把燈開一下!
燈打開了!!
-------------------------------------------------
小愛同學幫我關一下燈!
燈關上了!!

總結:

上面的例子僅僅是實現單個命令的的命令模式,而命令模式是可以相當複雜的,就比如說,你讓小愛同學幫你開啟燈,並且幫你開啟電視,並且開啟空調等等,這時候我們可以將多個命令儲存起來,然後一次性執行。

關於NoCommand的理解:

在沒有設定具體的命令的時候將命令儲存中的物件都設定成NoCommand的,這樣做可以避免空指標異常,具體作用體現可以閱讀《Head First》 。

關於巨集命令的理解:

將多個命令儲存起來,發出執行巨集命令請求的之後執行儲存的所有命令。

關於命令撤銷的理解:

在我們發出某個請求並執行之後,將命令的執行狀態進行儲存,如果我們想要回歸執行這個命令之前的狀態,我們就可以通過命令撤銷的方式迴歸到之前的狀態。

命令模式的優缺點:

優點:

  • 實現客戶端和接受者之間的解耦。
  • 可以動態的新增新的命令。
  • 只需要呼叫同一個方法(doCommand方法)便可以實現不同的功能。

缺點:

  • 實現一個具體的命令系統,可能要建立很多的具體命令物件。