策略模式 (Strategy Pattern)

January 3, 2022

本篇以條列式的方式,簡單描述策略模式的特色,並在文末附上範例。

特色

  • 藉由定義公用的 Interface,規範不同策略類別如何實作,並達到容易替換的效果。
  • 產生多個類別,減少 if-else 的長度。
  • 可搭配簡單工廠模式一同使用。其差異在於:簡單工廠模式關注不同物件如何被產生,而策略模式關注不同行為的使用。

缺點

  • 會產生很多類似的類別。因此可以搭配其它模式使用,如工廠模式。
  • 適用在常常需要變動的模組,若內部不太再需要變動,則不需要使用策略模式增加複雜度。

使用的時機

  • 單元測試注入假物件時。
  • 同樣行為,但使用不同的程式碼實作,例如各種繪畫的行為:實心方形、空心方形、實心圓形…。

範例

假如有個加油站提供不同車種的里程預估,用策略模式實作如下。

public class Strategy
{
    ///<summary> 車輛介面 </summary>
    protected interface ICar
    {
        public void AddFuel(int vol);
        public void CalcDistance();
    }

    ///<summary> 跑車類別 </summary>   
    protected class SportsCar : ICar
    {
        int fuel = 0;
        public void AddFuel(int vol)
        {
            this.fuel += vol;
        }
        public void CalcDistance()
        {
            double distance = fuel * 0.1;
            Console.WriteLine("Sports Car distance: " + distance);
        }
    }

    ///<summary> 轎車類別 </summary>
    protected class Sedan : ICar
    {
        int fuel = 0;
        public void AddFuel(int vol)
        {
            this.fuel += vol;
        }
        public void CalcDistance()
        {
            double distance = fuel * 0.3;
            Console.WriteLine("Sedan distance: " + distance);
        }
    }

    public void Run(int car)
    {
        // 原本的寫法
        // if (car == 0)
        // {
        //     SportsCar s = new SportsCar();
        //     s.AddFuel(100);
        //     s.CalcDistance();
        // }
        // else if(car == 1)
        // {
        //     Sedan s = new Sedan();
        //     s.AddFuel(100);
        //     s.CalcDistance();
        // }

        // 根據參數產生不同類別
        ICar s = GetCarInstance(0);
        // 保留相同的部分
        s.AddFuel(100);
        s.CalcDistance();
    }

    ///<summary> 策略模式,取得不同類別 </summary>
    protected ICar GetCarInstance(int car)
    {
        if(car == 0)
        {
            return new SportsCar();
        }
        else
        {
            return new Sedan();
        }
    }
}

參考資料

[ Day 3 ] 初探設計模式 - 策略模式 (Strategy Pattern)

[30天快速上手TDD][Day 17]Refactoring - Strategy Pattern - In 91 - 點部落