軟體設計模式系列之二十三——策略模式

cooldream2009發表於2023-10-04

1 模式的定義

策略模式(Strategy Pattern)是一種行為型設計模式,它允許在執行時動態選擇演算法的行為。這意味著你可以定義一系列演算法,將它們封裝成獨立的策略物件,然後根據需要在不修改客戶端程式碼的情況下切換這些演算法。策略模式有助於解決問題領域中不同行為的變化和擴充套件,同時保持程式碼的靈活性和可維護性。

2 舉例說明

策略模式在日常生活中有許多應用,以下是幾個比較符合策略模式且為大家所熟知的例子:

導航應用的路線選擇:導航應用根據使用者的輸入和當前交通情況,選擇不同的導航策略,如最短路徑、避開擁堵、步行導航等。使用者可以根據需要選擇不同的導航策略,類似於策略模式中的選擇不同演算法。

手機相機的拍攝模式:手機相機應用通常具有多種拍攝模式,如普通拍照、全景模式、夜間模式、慢動作模式等。使用者可以根據拍攝需求選擇不同的拍攝模式,每種模式對應不同的拍攝策略。

餐廳選單的點餐方式:在餐廳選單中,顧客可以選擇不同的點餐方式,如套餐、單點、外賣等。每種點餐方式對應不同的計費策略和服務流程。

交通訊號燈的控制:交通訊號燈會根據不同的時間段和交通流量採用不同的訊號控制策略,如紅燈、綠燈、黃燈。這些策略會在不同的情況下切換,以保障道路交通的安全和流暢。

這些例子中,策略模式的思想都可以看到:根據不同的需求或條件,選擇不同的策略來實現特定的行為或功能,而無需改變核心系統。這種動態選擇和切換策略的能力在日常生活中隨處可見,幫助我們更好地適應不同的情境和需求。

3 結構

策略模式通常包含以下角色:

Context(上下文):上下文類負責維護對策略物件的引用,並在執行時切換策略。上下文類通常具有一個方法,用於執行當前策略。

Strategy(策略):策略是一個介面或抽象類,定義了一組演算法的共同介面。具體的策略類實現這個介面,提供了不同的演算法實現。

ConcreteStrategy(具體策略):具體策略類實現了策略介面,提供了特定演算法的實現。

策略模式結構

4 實現步驟

實現策略模式通常包括以下步驟:

定義策略介面:建立一個策略介面或抽象類,定義演算法的方法。

建立具體策略類:為每個演算法建立具體的策略類,這些類應該實現策略介面,並提供自己的演算法實現。

建立上下文類:上下文類應該包含一個策略物件的引用,並提供方法來設定和執行策略。

在客戶端程式碼中使用:在客戶端程式碼中建立上下文物件,並根據需要設定不同的策略。

5 程式碼實現

讓我們透過Java程式碼來演示策略模式的實現。

// Step 1: 定義策略介面
interface DiscountStrategy {
    double applyDiscount(double amount);
}

// Step 2: 建立具體策略類
class PercentageDiscountStrategy implements DiscountStrategy {
    private double percentage;

    public PercentageDiscountStrategy(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public double applyDiscount(double amount) {
        return amount - (amount * percentage / 100);
    }
}

class FixedAmountDiscountStrategy implements DiscountStrategy {
    private double discountAmount;

    public FixedAmountDiscountStrategy(double discountAmount) {
        this.discountAmount = discountAmount;
    }

    @Override
    public double applyDiscount(double amount) {
        return amount - discountAmount;
    }
}

// Step 3: 建立上下文類
class ShoppingCart {
    private DiscountStrategy discountStrategy;

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double checkout(double totalAmount) {
        if (discountStrategy != null) {
            return discountStrategy.applyDiscount(totalAmount);
        }
        return totalAmount;
    }
}

// Step 4: 在客戶端程式碼中使用
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 使用百分比折扣策略
        cart.setDiscountStrategy(new PercentageDiscountStrategy(10));
        double discountedTotal = cart.checkout(100.0);
        System.out.println("Discounted Total: " + discountedTotal);

        // 使用固定金額折扣策略
        cart.setDiscountStrategy(new FixedAmountDiscountStrategy(20));
        discountedTotal = cart.checkout(100.0);
        System.out.println("Discounted Total: " + discountedTotal);
    }
}

6 典型應用場景

策略模式在許多不同的應用場景中都有廣泛的應用。以下是一些典型的策略模式應用場景以及簡要說明:

支付系統:支付系統通常需要處理多種支付方式,如信用卡、支付寶、微信支付等。策略模式可以用來實現每種支付方式的處理策略,使系統能夠根據使用者選擇的支付方式執行不同的支付邏輯。

電商平臺的促銷策略:電商平臺常常會推出不同的促銷活動,如打折、滿減、贈品等。策略模式可以用來實現這些促銷策略,使系統能夠根據當前活動動態地計算商品價格。

文字編輯器的文字格式化:文字編輯器可以提供多種文字格式化選項,如加粗、斜體、下劃線等。策略模式可以用來實現不同的文字格式化策略,使使用者能夠選擇不同的格式化效果。

遊戲開發中的敵人行為:在遊戲開發中,不同型別的敵人可能具有不同的行為,如追逐玩家、攻擊玩家、躲避玩家等。策略模式可以用來定義不同的敵人行為策略,使遊戲引擎能夠根據敵人的型別選擇正確的行為策略。

資料排序:在資料處理中,可能需要根據不同的排序演算法對資料進行排序,如快速排序、氣泡排序、插入排序等。策略模式可以用來實現這些不同的排序策略,使系統能夠根據資料量和性質選擇合適的排序演算法。

這些例子中,策略模式都用於動態選擇和切換不同的演算法或行為,以滿足不同的需求或情境。這種靈活性和可擴充套件性使得策略模式成為物件導向設計中的重要工具,能夠提高程式碼的可維護性和可讀性。

7 優缺點

優點:

策略模式使程式碼更具靈活性,易於擴充套件和維護。新增新的策略類不會影響現有程式碼。
策略模式將演算法封裝在獨立的策略類中,使程式碼更具可讀性和可維護性。
客戶端程式碼可以根據需要在執行時切換策略,無需修改現有程式碼。

缺點:

如果策略類數量過多,可能會導致類的數量增加,增加維護成本。
客戶端需要了解不同策略的存在,可能會增加複雜性。

8 類似模式

與策略模式類似的模式包括以下幾種:

狀態模式(State Pattern):

狀態模式和策略模式都屬於行為型設計模式,它們都關注物件的行為,但它們的重點不同。策略模式側重於在一組演算法中選擇一個,而狀態模式側重於在物件的狀態改變時改變其行為。在狀態模式中,物件的行為取決於它的狀態,而不是透過外部切換不同的策略類。

命令模式(Command Pattern):

策略模式和命令模式都允許將不同的行為封裝成物件,但它們的目的和用途有所不同。策略模式用於在執行時選擇不同的演算法,而命令模式用於封裝請求以及請求的引數,允許以更靈活的方式進行操作。

模板方法模式(Template Method Pattern):

模板方法模式和策略模式都是用於定義一組演算法,但它們的關注點不同。模板方法模式定義了一個演算法的骨架,具體子類可以實現其中的某些步驟,而策略模式將不同的演算法封裝成獨立的策略物件,並允許在執行時選擇不同的策略。

這些模式之間的聯絡在於它們都涉及到將不同的行為封裝成物件,從而提高了程式碼的可維護性和靈活性。然而,它們各自解決不同型別的問題,因此在選擇模式時需要根據具體情況來決定使用哪種模式。策略模式更適用於需要在一組演算法中進行動態選擇的情況,而其他模式則解決了不同的設計問題,例如狀態管理、請求封裝等。根據問題的性質,可以選擇合適的模式來實現所需的功能。

9 小結

策略模式是一種強大的設計模式,允許在執行時選擇不同的演算法實現,以處理不同的行為需求。透過將演算法封裝在獨立的策略類中,策略模式提高了程式碼的可維護性和可擴充套件性。在面臨多種行為選擇的情況下,策略模式是一個有力的工具,可以使程式碼更加靈活和可讀。但是,它需要在客戶端了解不同策略的情況下使用,因此需要謹慎設計。總之,策略模式是物件導向設計中的一個重要概念,值得深入學習和應用。

相關文章