軟體設計模式系列之十六——命令模式

cooldream2009發表於2023-09-27

1 模式的定義

命令模式(Command Pattern)是一種行為型設計模式,旨在將請求傳送者和接收者解耦,將一個請求封裝為一個物件,從而允許您引數化客戶端物件以進行不同的請求、排隊請求或記錄請求,並支援可撤銷操作。

命令模式的核心思想是將一個請求包裝成一個物件,包括請求的引數和接收者物件,然後客戶端只需要呼叫該物件的方法來執行請求,而不需要關心請求的具體細節。這種方式使得請求的傳送者和接收者之間的關係變得松耦合,同時支援一些附加功能,如命令的撤銷和重做。

2 舉例說明

為了更好地理解命令模式,讓我們考慮一個實際的例子:遙控器控制家電。假設您有一個遙控器,可以控制不同種類的家電裝置,如電視、音響和燈。每個按鈕都代表一個命令,例如開啟電視、關閉音響、調暗燈光等。命令模式可以用於實現這種遙控器系統。

在這個例子中,每個命令(如開啟電視)都被封裝成一個命令物件,包括具體的操作(執行命令)和接收者物件(執行命令的裝置)。遙控器上的按鈕只需要關聯一個命令物件,並在按下按鈕時執行該命令。這種方式使得遙控器可以輕鬆控制不同種類的家電裝置,而不需要關心它們的具體實現。

3 結構

命令模式的結構包括以下幾個關鍵部分:

Command(命令):定義一個執行操作的介面,通常包括一個 execute 方法,負責執行具體的命令。

ConcreteCommand(具體命令):實現命令介面,將一個接收者物件繫結到一個操作。它負責呼叫接收者的方法來執行命令。

Receiver(接收者):負責執行與請求相關的具體操作,是命令真正的執行者。

Invoker(呼叫者):負責將命令物件傳遞給接收者執行命令,它不需要知道命令的具體細節,只需呼叫命令的 execute 方法即可。

Client(客戶端):建立具體命令物件,並將命令物件與接收者物件關聯,然後將命令物件傳遞給呼叫者來執行。

4 實現步驟

實現命令模式時,通常遵循以下步驟:

定義命令介面(Command),其中包括一個 execute 方法用於執行命令。

建立具體命令類(ConcreteCommand),實現命令介面,並在建構函式中繫結一個接收者物件。

定義接收者類(Receiver),負責執行具體的操作。

建立呼叫者類(Invoker),負責接收命令物件並執行命令。

在客戶端中建立命令物件和接收者物件,並將它們關聯。然後將命令物件傳遞給呼叫者,由呼叫者執行命令。

5 程式碼實現

現在,讓我們透過 Java 程式碼來實現上述遙控器控制家電的命令模式。

// 1. 定義命令介面
interface Command {
    void execute();
}

// 2. 建立具體命令類
class LightOnCommand implements Command {
    private Light light;

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

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

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

    @Override
    public void execute() {
        light.turnOff();
    }
}

// 3. 定義接收者類
class Light {
    public void turnOn() {
        System.out.println("Light is on");
    }

    public void turnOff() {
        System.out.println("Light is off");
    }
}

// 4. 建立呼叫者類
class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

// 5. 客戶端程式碼
public class Client {
    public static void main(String[] args) {
        // 建立接收者物件
        Light light = new Light();

        // 建立具體命令物件並關聯接收者
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        // 建立呼叫者
        RemoteControl remote = new RemoteControl();

        // 設定命令並執行
        remote.setCommand(lightOn);
        remote.pressButton();

        remote.setCommand(lightOff);
        remote.pressButton();
    }
}

6 典型應用場景

命令模式在實際應用中有多種典型場景,包括但不限於:

遙控器控制:如上面的示例所示,可以用命令模式實現遙控器來控制不同的家電裝置,如電視、音響和燈。

文字編輯器操作:文字編輯器中的撤銷、重做、剪下、複製、貼上等操作可以使用命令模式來實現。

選單系統:圖形使用者介面(GUI)應用中的選單項和按鈕操作可以透過命令模式來處理。

遊戲中的動作:在遊戲中,角色的動作和命令(如攻擊、防禦、跳躍等)可以使用命令模式來處理。

多級撤銷操作:命令模式支援撤銷和重做操作,因此在需要多級撤銷的應用中很有用,如影像編輯器或CAD軟體。

日程安排應用:在日程安排應用中,可以使用命令模式來處理新增、編輯、刪除事件等操作。

7 優缺點

優點:

解耦傳送者和接收者:命令模式將請求的傳送者和接收者解耦,傳送者不需要知道接收者的具體實現,從而降低了系統的耦合度。

支援撤銷和重做:命令模式可以輕鬆支援命令的撤銷和重做,因為每個命令物件都包含了執行和撤銷操作的邏輯。

支援擴充套件:可以輕鬆新增新的命令和接收者,而無需修改現有的客戶端程式碼。

支援排隊請求:命令模式允許將請求排隊,以便按照先後順序執行,或者實現任務排程。

缺點:

可能導致命令類膨脹:如果有大量的命令操作,可能會導致命令類的膨脹,增加維護的複雜性。

不適用於所有情況:命令模式不適用於所有場景,特別是對於簡單的命令,直接呼叫方法可能更加簡單和高效。

增加程式碼複雜性:引入命令模式會增加一定的程式碼複雜性,因為需要建立額外的命令類和接收者類。

8 類似模式

策略模式(Strategy Pattern):策略模式也可以用於封裝可互換的行為,但它的主要目的是在執行時選擇演算法或策略,而不是將請求封裝成命令物件。

觀察者模式(Observer Pattern):觀察者模式用於定義物件之間的一對多依賴關係,當一個物件狀態發生變化時,所有依賴於它的物件都會收到通知。與命令模式不同,觀察者模式不涉及命令的封裝和執行。

中介者模式(Mediator Pattern):中介者模式用於減少物件之間的直接耦合,將物件之間的通訊集中在一箇中介者物件中。與命令模式不同,中介者模式通常用於管理物件之間的互動,而不是將請求封裝成命令。

9 小結

命令模式是一種有用的設計模式,它允許將請求封裝成命令物件,從而解耦請求的傳送者和接收者,支援撤銷和重做操作,並提供擴充套件性和靈活性。命令模式在實際應用中有多種典型場景,包括遙控器控制、文字編輯器操作、選單系統等。雖然命令模式增加了一些複雜性,但它可以提高程式碼的可維護性和可擴充套件性,是物件導向設計中的重要模式之一。

相關文章