1. 程式人生 > 實用技巧 >設計模式(22) 策略模式

設計模式(22) 策略模式

在策略模式中,一個類的行為或演算法可以在執行時動態更改。

GOF對策略模式的描述為:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients.
— Design Patterns : Elements of Reusable Object-Oriented Software

UML類圖如下:

策略模式包含三個角色:

  • Context上下文角色,起承上啟下封裝作用,遮蔽高層模組對策略、演算法的直接訪問,封裝可能存在的變化。
  • Strategy抽象策略角色,策略、演算法家族的抽象,通常為介面,定義每個策略或演算法必須具有的方法和屬性。
  • ConcreteStrategy具體策略角色,實現抽象策略中的操作,該類含有具體的演算法。

程式碼示例:
以電商會員折扣為例,不同級別的會員享受的折扣是不同的,這種差異可以用策略模式來封裝。

public interface Strategy
{
    double CalcPrice(double originalPrice);
}

public class PrimaryStrategy : Strategy
{
    public double CalcPrice(double originalPrice)
    {
        return originalPrice;
    }
}

public class IntermediateStrategy : Strategy
{
    public double CalcPrice(double originalPrice)
    {
        return originalPrice * 0.9;
    }
}
public class AdvancedStrategy : Strategy
{
    public double CalcPrice(double originalPrice)
    {
        return originalPrice * 0.8;
    }
}

public class PriceContext
{
    public Strategy Strategy { get; set; }

    public double GetPrice(double originalPrice)
    {
        return this.Strategy.CalcPrice(originalPrice);
    }
}

呼叫端:

public class Test
{
    public static void Entry()
    {
        Strategy strategy = new PrimaryStrategy();
        PriceContext price = new PriceContext();
        price.Strategy = strategy;

        Console.WriteLine(price.GetPrice(100)); //100

        strategy = new IntermediateStrategy();
        price.Strategy = strategy;
        Console.WriteLine(price.GetPrice(100)); //90

        strategy = new AdvancedStrategy();
        price.Strategy = strategy;
        Console.WriteLine(price.GetPrice(100)); //80
    }
}

示例中有若干具體的策略類,以及一個context物件,context物件會隨著策略物件的改變而變更其執行演算法。

策略模式的優點

  • 演算法可以自由切換,只要實現抽象策略,它就成為策略家族的一個成員,通過封裝角色對其進行封裝,保證對外提供“可自由切換”的策略。
  • 避免使用多重條件判斷,多重條件語句不易維護,而且出錯的概率較大。使用策略模式後,可以由其他模組決定採用何種策略,策略家族對外提供的訪問介面就是封裝類,簡化了操作,同時避免了條件語句判斷。
  • 擴充套件性良好,在現有的系統中增加一個策略非常容易,只要實現介面就可以了。

策略模式的缺點

  • 策略類數量增多,每一個策略都是一個類,複用的可能性很小,類數量增多。
  • 所有的策略類都需要對外暴露,上層模組必須知道有哪些策略,並瞭解這些策略之間的區別,然後才能決定使用哪一個策略,這與迪米特法則是相違背的。

策略模式的適用場景

  • 多個類只有在演算法或行為上稍有不同的場景。
  • 演算法需要自由切換的場景。