【大話設計模式】——策略模式

ZeroWM發表於2014-05-27

一、開篇

  上篇文章【大話設計模式】——簡單工廠模式告訴了我們一個網咖收費工廠物件如何建立收費形式(白天收費、夜間收費)的例項。簡單工廠程式碼中有很多 case分支語句 ,如果我們還想填加收費的形式(比如會員收費啊,通宵收費啊),就需要改動工廠程式碼,每次維護和擴充套件都要花費很多時間,另外改動很容易造成紕漏(比如之前的白天收費形式,很可能因為改動從多收錢或者少收錢),所以簡單工廠模式很不安全。所以我們要把經常變化的程式碼抽象出來,做到業務邏輯介面邏輯分開,只有這樣才能更加容易做到維護和擴充套件。

  發現問題,解決問題,人類就這樣一點一滴的進步著。

  發現了簡單工廠的不好,策略模式就誕生啦,人類真的是很睿智!(呱唧呱唧)

  下面大家熟悉一下策略模式的定義:

  策略模式(Strategy):它定義了演算法家族,分別封裝起來,讓她們之間可以互相替換,此模式讓演算法的變化,不會影響到使用演算法的客戶。


二、UML圖

Context(環境類):需要使用ConcreteStrategy的具體演算法,維護一個對Strategy物件的引用,負責跟Strategy之間的互動和資料傳遞。

Strategy(抽象策略類):定義所有支援的演算法的公共介面。Context使用這個介面來呼叫ConcreteStrategy演算法。

ConcreteStrategy(具體策略類):封裝了具體的演算法和行為,繼承與Strategy.

圖中含有兩種關係,聚合和繼承。



三、例項解析

比如我們填飽肚子的方式,有幾個策略可以考慮:吃水果、吃蔬菜、吃饅頭。首先定義一個抽象類吃,然後讓吃的形式:吃水果,吃蔬菜,吃饅頭繼承這個抽象吃類,再宣告一個Context類,用來配置吃的方法,維護一個對Strategy物件的引用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication7
{
    class Program
    {
        static void Main(string[] args)//客戶端程式碼
        {
            Context context;
            context = new Context(new EatingFruit());//例項化不同的策略,呼叫的時候獲得的結果就不同。
            context.ContextInterface();

            context = new Context(new EatingVegetables());
            context.ContextInterface();

            context = new Context(new EatingSteamBread());
            context.ContextInterface();
        }
    }


    abstract class EatStrategy//抽象吃法類
    {
        public abstract void Eat();
    }

    class EatingFruit:EatStrategy //具體吃法吃蘋果 
    {
        public override void Eat()
        {
            Console .WriteLine ("餓了吃蘋果");
        }
    }
    class EatingVegetables : EatStrategy//具體吃法吃蔬菜
    {
        public override void Eat()
        {
            Console .WriteLine ("吃蔬菜也不餓");
        }
    }
    class EatingSteamBread : EatStrategy//具體吃法吃饅頭
    {
        public override void Eat()
        {
            Console .WriteLine ("吃饅頭也不錯");
        }
    }

    class Context//寫策略環境類
    {
        EatStrategy eatstrategy;
        public Context(EatStrategy eatstrategy)//初始化時,傳入具體的策略物件
        {
            this.eatstrategy = eatstrategy;
        }
        //上下文介面
        public void ContextInterface()//根據具體的策略物件,呼叫其演算法的方法
        {
            eatstrategy.Eat();
        }
    }
    
}


四、總結

策略模式的優點:

1)所有的演算法完成相同的工作,只是實現不同,它以相同的方式呼叫所有的演算法,減少了各種演算法類與使用演算法類之間的耦合。

個人理解:不管是吃水果還是吃蔬菜,異或是吃饅頭,都是為了填飽肚子,雖然形式不同,如果有的人挑食吃飯一定要吃菜加饅頭才肯吃,那如果沒有賣饅頭的,你就要減肥啦~

2)策略模式Strategy類層次為Context定義了一系列的可供重用的演算法和行為。繼承有助於析取出這些演算法中的公共功能。

個人理解:把東西分類放置,使用的時候就更加容易找到。

3)簡化了單元測試,因為每個演算法都有自己的類,可以通過自己的介面單獨測試。

個人理解:有單獨的類,就更容易滿足單一職責原則,這樣測試一個功能,資料如果不對,直接就能劃分出範圍。比如值日分為掃地和擦桌子,安排小明拖地,小紅擦桌子。如果值完日了,地面還髒,那肯定就是小明乾的不好唄(當然排除搞破壞的可能)。但是如果你讓兩個人幹活,又沒有分配任務,那好了,挨罰就兩個人一起做個伴吧!

4)演算法封裝在單獨的類中,可以消除條件語句,為客戶端減輕了壓力。

個人理解領導者如果負責一個很龐大的工程的話,那些瑣事會讓他侷限於細節,而失去了把控能力。


缺點:

1)客戶端必須知道所有的策略類,並自行決定使用哪個策略類。

2)Strategy和Context之間存在通訊開銷

3)如果具體策略過多,會產生很多的策略類,增加了維護的難度。

  

程式碼即人生啊~




相關文章