Java設計模式(16)----------命令模式

ldzsl發表於2021-09-09
介紹

命令模式是一種行為型設計模式。在命令模式中,所有的請求都會被包裝成為一個物件。

參考了一下其他關於命令模式的文章,其中有談到說是可以用不同的請求對客戶進行引數化。我對這句話的理解是,因為將請求封裝成為物件,所以客戶的所有操作,其實就是多個命令類的物件而已,即引數化了。

命令模式的最大的特點就是將請求的呼叫者與請求的最終執行者進行了解耦。呼叫者需要關心的僅僅是請求物件是否被執行了,對於請求物件是如何執行的,對什麼進行操作的,統統不需要關心。

原理:命令模式中,一般有如下幾個角色:

  • command:命令的抽象介面,其中包含execute方法。根據業務需求,有的還會包含其他通用方法如undo等。
  • concreteCommand:具體的命令實現類。每一種請求,都會對映一個具體的命令實現類。對於每個類,都會實現execute方法,並且依賴receiver,也就是接收者物件。execute方法中,一般就是呼叫接收者物件的對應方法,從而實現對請求的最終處理。
  • receiver:請求的接收者,也是請求的最終的執行者,被命令實現類所依賴。
  • invoker:請求的呼叫者。呼叫者會呼叫所有傳入的命令物件的execute方法,開啟命令的執行,但是不會與最終的執行者receive耦合,兩者中間是透過命令實現類進行聯絡和溝通的。
  • client:進行接收者物件和命令物件的建立,並建立兩者之間的聯絡。

適用場景:涉及到“命令”、“操作”或者“控制”的場景,一般都是命令模式的適用場景。

  • 餐廳點菜的過程,消費者(client)說要吃某幾種菜(命令物件),趕快做好端上來。服務員(invoker)會記錄所有點過的菜品(儲存所有的命令物件),然後將訂單給後廚說,按照單子做(呼叫所有命令物件的execute)。之後就會啟動每一道菜品的製作流程。對於菜品如何烹製,與服務員是沒有關係的,兩者不耦合。
  • 遙控器的執行過程也可以理解成是一種命令模式的應用。假設有一個智慧家居的遙控器,在皮膚上,可以控制電燈的開關,空調的開關(各種命令物件)。遙控器就是invoker的角色,負責實際命令的呼叫。而最終命令的執行,則是各種電器(receiver)來進行的。
  • 多執行緒的執行,也可以理解為一種命令模式的應用。
    案例
    背景

    我們以智慧家居的遙控器為例。手頭上有一個智慧遙控器(invoker),能夠控制開啟電燈,關閉電燈,開啟電視,關閉電視等操作。

    實現

    定義命令介面

public interface Command {
    void execute();
}

定義receiver

public class Light {
    public void open()
    {
        System.out.println("Light is open");
    }
    public void close()
    {
        System.out.println("Light is closed");
    }
}
public class TV {
    public void open()
    {
        System.out.println("TV is open");
    }
    public void close()
    {
        System.out.println("TV is closed");
    }
}

定義具體命令

public class OpenLignt implements Command {
    private Light light;

    public OpenLignt(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        this.light.open();
    }
}
public class CloseLight implements Command {
    private Light light;

    public CloseLight(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        this.light.close();
    }
}
public class OpenTV implements Command {
    private TV tv;

    public OpenTV(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.open();
    }
}
public class CloseTV implements Command {
    private TV tv;

    public CloseTV(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.close();
    }
}

定義遙控器(invoker)

public class Controller {
    private Command[] buttons;
    private int num = 0;

    public Controller() {
        buttons = new Command[10];
    }

    public void addButton(Command command)
    {
        buttons[num++] = command;
    }

    public void pushButton(int number)
    {
        if (number > -1 && number 

驗證程式

public class Test {
    public static void main(String[] args){
        Light light = new Light();
        TV tv = new TV();

        Controller controller = new Controller();
        controller.addButton(new OpenLignt(light));
        controller.addButton(new CloseLight(light));
        controller.addButton(new OpenTV(tv));
        controller.addButton(new CloseTV(tv));

        controller.pushButton(0);
        controller.pushButton(1);
        controller.pushButton(2);
        controller.pushButton(3);
    }
}

程式輸出

Light is open
Light is closed
TV is open
TV is closed

Process finished with exit code 0

擴充套件

命令模式中有一種擴充套件,叫做宏命令,能同時進行一組命令的執行。比如遙控器只存在兩個按鍵,一個控制所有電器的開啟,一個控制所有電器的關閉。那麼我們不需要改動已有的程式碼,只要擴充套件一個組合命令類,其中包含多個命令即可。

public class MutilCommand implements Command {
    private Command[] commands;

    public MutilCommand(Command[] commands) {
        this.commands = commands;
    }

    @Override
    public void execute() {
        for (Command command : commands)
        {
            command.execute();
        }
    }
}

驗證程式

public class Test {
    public static void main(String[] args){
        Light light = new Light();
        TV tv = new TV();

        Controller controller = new Controller();
        controller.addButton(new OpenLignt(light));
        controller.addButton(new CloseLight(light));
        controller.addButton(new OpenTV(tv));
        controller.addButton(new CloseTV(tv));

        controller.addButton(new MutilCommand(new Command[]{new OpenLignt(light), new OpenTV(tv)}));
        controller.addButton(new MutilCommand(new Command[]{new CloseLight(light), new CloseTV(tv)}));

        controller.pushButton(0);
        controller.pushButton(1);
        controller.pushButton(2);
        controller.pushButton(3);
        System.out.println("");
        controller.pushButton(4);
        controller.pushButton(5);
    }
}

執行結果

Light is open
Light is closed
TV is open
TV is closed

Light is open
TV is open
Light is closed
TV is closed

Process finished with exit code 0

總結

命令模式的核心思想就是將命令或者請求封裝成物件,分離請求呼叫者和請求最終執行者。

優點:將請求呼叫者和執行者解耦。

缺點:如果存在較多的命令或者請求,需要較多的命令類。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2325/viewspace-2800017/,如需轉載,請註明出處,否則將追究法律責任。

相關文章