[Design Pattern] Stragegy Pattern

自由擴充及切換演算法(功能)

官方說明

定義演算法家族且個別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變動獨立於使用操作物件之外

PS. [家族]表示各演算法(功能)作用相似

 

主要療效

自由擴充及切換演算法(功能)

以IStragegy介面作為Context掛載各ConcreteStragegy的邊界,Context可以隨意切換任何ConcreteStragegy來執行任務;另外,可以當有新的ConcreteStrategy被擴充時,也可輕易的被Context掛載使用。

image

 

適用情況

1. 會不斷擴充的演算法(功能)家族

2. 用戶會切換使用不同演算法(功能)

    PS. [家族]表示各演算法(功能)作用相同

 

關鍵心法

1. 將演算法家族必備部分抽出為介面

2. 實作介面之個別演算法

3. 將演算法實體注入用戶中進行操作

 

應用聯想

開發一隻檔案壓縮程式,預計區分為三種產品線,依序為免費版、去廣告板及企業版,分別使用公司開發的三種壓縮演算方法(普通壓縮、中級壓縮、高級壓縮)。

 

首先來檢查是否合乎適用情境:

1. 會不斷擴充的演算法(功能)家族

    壓縮演算法(ICompressAlgorithm)會不斷的研發精進

    PS. 此處[家族]表示各演算法(功能)作用相同,演算法的功能都是作為檔案壓縮使用

2. 用戶會切換使用不同演算法(功能)

    銷售產品(Zipper)會依照行銷策略or新演算法問世而調整演算法的使用

 

實際演練

筆者將搭配關鍵心法來套用策略模式,讓各演算法(ICompressAlgorithm)與產品(Zipper)的耦合性降低,可以輕易地擴充新演算法,且讓產品也可隨意使用。

image

 

1. 將演算法家族必備部分抽出為介面

    由於各演算法的作用為檔案壓縮,所以抽出壓縮(Compress)作業為介面

interface ICompressAlgorithm
{
    // 檔案壓縮
    void Compress();
}

 

2. 實作介面之個別演算法

    建立個別檔案壓縮演算法(實作ICompressAlgorithm介面)

class NormalCompressAlgorithm : ICompressAlgorithm
{
    public void Compress()
    {
        Console.WriteLine("普通壓縮");
    }
}

class MidLevelCompressAlgorithm : ICompressAlgorithm
{
    public void Compress()
    {
        Console.WriteLine("中級壓縮");
    }
}

class HighLevelCompressAlgorithm : ICompressAlgorithm
{
    public void Compress()
    {
        Console.WriteLine("高級壓縮");
    }
}

 

3. 將演算法實體注入用戶中進行操作

    * 使用時可以自行組裝產品與其使用之壓縮演算法。

    * 切斷了產品與演算法之間的耦合

    * 產品只知道需要壓縮,而實際壓縮的方式是透過外部注入的物件來執行。

class Zipper
{
    // Fields
    private ICompressAlgorithm _compressAlgorithm;


    // Constructors
    public Zipper(ICompressAlgorithm compressAlgorithm)
    {
        _compressAlgorithm = compressAlgorithm;
    }


    // Methods
    public void Compress()
    {
        if (_compressAlgorithm != null)
            _compressAlgorithm.Compress();
    }
}

 

static void Main(string[] args)
{
	// 檔案壓縮產品(三種)
    Zipper normalZipper;
    Zipper noAdZipper;
    Zipper enterpriseZipper;

    // 免費版: 注入普通壓縮演算法
    Console.WriteLine("Normal Zipper:");
    normalZipper = new Zipper(new NormalCompressAlgorithm());
    normalZipper.Compress();

    // 去廣告板: 注入中效壓縮演算法
    Console.WriteLine("No Ad Zipper:");
    noAdZipper = new Zipper(new MidLevelCompressAlgorithm());
    noAdZipper.Compress();

    // 企業版: 注入高效壓縮演算法
    Console.WriteLine("Enterprise Zipper:");
    enterpriseZipper = new Zipper(new HighLevelCompressAlgorithm());
    enterpriseZipper.Compress();

    Console.ReadKey();
}

image

 

總結

透過以上實例可發現,套用策略模式可使產品(Zipper)與演算法(ICompressAlgorithm)各司其職,當需產生一新式演算法時,僅需新建類別且實作檔案壓縮演算法介面即可(擴充性高),並不影響任何產品的運作(耦合性低),且針對產品在使用新式演算法上,也只需注入該演算法實體即可,不用對產品類別進行修改(封閉原則);若以此角度設計,將來在系統維護上必定可減經開發者不少的負擔,且功德無量好事一件啊!! XD

 

若想比較使用前後效益,請參考以下重構系列文章:

[Refactoring] 使用策略模式(Strategy Pattern)進行重構

 

參考資料

http://teddy-chen-tw.blogspot.tw/2013/08/strategy-pattern.html

http://www.dotblogs.com.tw/joysdw12/archive/2013/03/07/95769.aspx


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !