天天看點

設計模式-指令模式

設計模式-指令模式

1.問題引出

智能生活項目需求

  1. 我們買了一套智能家電,有照明燈、風扇、冰箱、洗衣機,我們隻要在手機上安裝app就可以控制對這些家電工作。
  2. 這些智能家電來自不同的廠家,我們不想針對每一種家電都安裝一個App,分别控制,我們希望隻要一個app就可以控制全部智能家電。
  3. 要實作一個app控制所有智能家電的需要,則每個智能家電廠家都要提供一個統一的接口給app調用,這時 就可以考慮使用指令模式。
  4. 指令模式可将“動作的請求者”從“動作的執行者”對象中解耦出來.
  5. 在我們的例子中,動作的請求者是手機app,動作的執行者是每個廠商的一個家電産品
  1. 指令模式(Command Pattern):在軟體設計中,我們經常需要向某些對象發送請求,但是并不知道請求的接收者是誰,也不知道被請求的操作是哪個,我們隻需在程式運作時指定具體的請求接收者即可,此時,可以使用指令模式來進行設計
  2. 命名模式使得請求發送者與請求接收者消除彼此之間的耦合,讓對象之間的調用關系更加靈活,實作解耦。
  3. 在命名模式中,會将一個請求封裝為一個對象,以便使用不同參數來表示不同的請求(即命名),同時指令模式也支援可撤銷的操作。
  4. 通俗易懂的了解:将軍釋出指令,士兵去執行。其中有幾個角色:将軍(指令釋出者)、士兵(指令的具體執行者)、指令(連接配接将軍和士兵)。Invoker是調用者(将軍),Receiver是被調用者(士兵),MyCommand是指令,實作了Command接口,持有接收對象
package command;

public interface Command {

    //執行動作(操作)
    public void execute();

    //撤銷動作(操作)
    public void undo();
}
           
package command;

public class LightOnCommand implements Command{

    LightReceive light;

    //構造器


    public LightOnCommand(LightReceive light) {
        this.light = light;
    }

    @Override
    public void execute() {
        //調用接收者的方法
        light.on();
    }

    @Override
    public void undo() {
        //調用接收者的方法
        light.off();
    }
}
           
package command;

public class LightOffCommand implements Command{
    LightReceive light;

    //構造器


    public LightOffCommand(LightReceive light) {
        this.light = light;
    }

    @Override
    public void execute() {
        //調用接收者的方法
        light.off();
    }

    @Override
    public void undo() {
        //調用接收者的方法
        light.on();
    }
}

           
package command;

public class NoCommand implements Command{
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}
           
package command;

public class LightReceive {
    public void on(){
        System.out.println("電燈打開了");
    }

    public void off(){
        System.out.println("電燈關閉了");
    }
}
           
package command;

public class RemoteController {
    //開關按鈕的指令數組
    Command[] onCommands;
    Command[] offCommands;

    //執行撤銷的指令
    Command undoCommand;

    //構造器,完成對按鈕的初始化

    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    public void setCommand(int no,Command onCommand,Command offCommand){
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    //按下開按鍵
    public void onButtonWasPushed(int no){
        //找到你按下的開的按鈕,并調用對應的方法
        onCommands[no].execute();
        //記錄這次的操作,用于撤銷
        undoCommand = onCommands[no];
    }

    //按下關按鍵
    public void offButtonWasPushed(int no){
        //找到你按下的關的按鈕,并調用對應的方法
        offCommands[no].execute();
        //記錄這次的操作,用于撤銷
        undoCommand = offCommands[no];
    }

    //按下撤銷按鍵
    public void undoButtonWasPushed(int no){
        undoCommand.undo();
    }

}
           
package command;

public class Client {
    public static void main(String[] args) {
        //建立電燈的對象(接受者)
        LightReceive lightReceive = new LightReceive();

        //建立電燈相關的開關指令
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceive);

        LightOffCommand lightOffCommand = new LightOffCommand(lightReceive);

        //需要一個遙控器
        RemoteController remoteController = new RemoteController();

        //給我們的遙控器設定指令
        remoteController.setCommand(0,lightOnCommand,lightOffCommand);

        //按下按鈕
        remoteController.onButtonWasPushed(0);
        remoteController.offButtonWasPushed(0);
        remoteController.undoButtonWasPushed(0);
    }
}
           
  1. 将發起請求的對象與執行請求的對象解耦。發起請求的對象是調用者,調用者隻要調用指令對象的execute()方法就可以讓接收者工作,而不必知道具體的接收者對象是誰、是如何實作的,指令對象會負責讓接收者執行請求的動作,也就是說:”請求發起者”和“請求執行者”之間的解耦是通過指令對象實作的,指令對象起到了紐帶橋梁的作用。
  2. 容易設計一個指令隊列。隻要把指令對象放到列隊,就可以多線程的執行指令
  3. 容易實作對請求的撤銷和重做
  4. 指令模式不足:可能導緻某些系統有過多的具體指令類,增加了系統的複雜度,這點在在使用的時候要注意
  5. 空指令也是一種設計模式,它為我們省去了判空的操作。在上面的執行個體中,如果沒有用空指令,我們每按下一個按鍵都要判空,這給我們編碼帶來一定的麻煩。
  6. 指令模式經典的應用場景:界面的一個按鈕都是一條指令、模拟CMD(DOS指令)訂單的撤銷/恢複、觸發-回報機制
下一篇: 檔案系統