2013年8月31日 星期六

設計模式:策略模式 (Strategy Pattern)

策略模式 (Strategy Pattern),以下程式碼以 C# 為例

說明:
將不同的演算法,定義成一個家族,
這些演算法實現同樣的接口,且寫成個別的類別,所以彼此之間能夠互相替換。
優點是以後要增加新的演算法,只須額外新增一個類別,不須動到原本的類別。

範例:
商店在不同的時期,常會有不同的折扣活動。假設有「打8折」、「打7折」、「滿200打6折」,這些不同的算法則可用策略模式來實做,以後如果又有新的折扣活動,只須再新增一個算法類別即可,不須更動到原本的計算類別。


希望達成如下的效果
static void Main(string[] args)
{
    CashContext cc;
    // 打8折的時候
    cc = new CashContext(new ConcreteStrategyA());
    cc.ExecuteStrategy(100);

    // 打7折的時候
    cc = new CashContext(new ConcreteStrategyB());
    cc.ExecuteStrategy(100);

    // 滿200打6折的時候
    cc = new CashContext(new ConcreteStrategyC());
    cc.ExecuteStrategy(200);

    Console.Read();
}
執行結果: 
原價 100, 打8折 = 80
原價 100, 打7折 = 70
原價 200, 滿200打6折 = 120


實現重點在於,演算法要實現同樣的接口,才能讓 context 類別能用同樣的方式,操作不同的演算法。

其餘程式碼
// 策略介面,定義一個演算法要實做的方法
interface Strategy
{
    void Execute(int money);
}

// 第一種算法,打 8 折
class ConcreteStrategyA : Strategy
{
    public void Execute(int money)
    {
        double res = money * 0.8;
        Console.WriteLine("原價 {0}, 打8折 = {1}", money, res);
    }
}

// 第二種算法,打 7 折
class ConcreteStrategyB : Strategy
{
    public void Execute(int money)
    {
        double res = money * 0.7;
        Console.WriteLine("原價 {0}, 打7折 = {1}", money, res);
    }
}

// 第三種算法,滿 200 打 6 折
class ConcreteStrategyC : Strategy
{
    public void Execute(int money)
    {
        double res = (money >= 200) ? money * 0.6 : money;
        Console.WriteLine("原價 {0}, 滿200打6折 = {1}", money, res);
    }
}

// 用來維護策略物件的類別
class CashContext
{
    Strategy strategy; // 算法物件

    public CashContext(Strategy strategy)
    {
        this.strategy = strategy;
    }
    public void ExecuteStrategy(int money)
    {
        this.strategy.Execute(money);
    }
}

相關連結:設計模式整理列表

沒有留言:

張貼留言