設計模式學習筆記-策略模式


  在講策略模式之前,我先給大家舉個日常生活中的例子,從首都國際機場到XXX酒店,怎么過去?1)酒店接機服務,直接開車來接。2)打車過去。3)機場快軌+地鐵 4)機場巴士 5)公交車 6)走路過去(不跑累死的話) 等等。使用方法,我們都可以達到從機場到XXX酒店的目的,對吧。那么我所列出的從機場到XXX酒店的的方法,就是我們可以選擇的策略。

  再舉個例子,就是我們使用WCF時,往往避免不了對它進行擴展,例如授權,我們可以通過自定義授權來擴展WCF。這里我們可以通過自定義AuthorizationPolicy和ServiceAuthorizationManager來實現對它的擴展,這是策略模式的一個真實應用。

1. 概述

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

2. 模式中的角色

  2.1 策略類(Stratege):定義所有支持的算法的公共接口。

  2.2 具體策略類(Concrete Stratege):封裝了具體的算法或行為,繼承於Stratege類。

  2.3 上下文類(Context):用一個ConcreteStratege來配置,維護一個對Stratege對象的引用。

  對比開篇例子分析一下這個模式中的角色:

  在從機場到XXX酒店的這個例子中,策略類中必然要包括GoToHotel這個方法。而具體策略類應該實現或繼承策略類,它的實現就不用說了。上下文類,這個類很重要,也很有意思,因為它需要去選擇使用哪個策略,例如這個上下我是我,我要從機場到XXX酒店,1)我根本不差錢,酒店也提供接機服務,那我必然選擇酒店接機呀;2)如果酒店不提供接機我就選擇打的。3)如果我囊中羞澀,就可以選擇公共交通。4)如果我現在錢都花完了,連吃飯的錢都沒有了,那么我只能選擇走路過去了,沒准半道上還得討飯呢!

3. 模式解讀

  3.1 策略模式的一般化類圖

  

  3.2 策略模式的代碼實現

    /// <summary>
    /// 策略類,定義了所有支持的算法的公共接口
    /// </summary>
    public abstract class Stratege
    {
        /// <summary>
        /// 策略類中支持的算法,當然還可以有更多,這里只定義了一個。
        /// </summary>
        public abstract void Algorithm();
    }

    /// <summary>
    /// 具體策略 A,實現了一種具體算法
    /// </summary>
    public class ConcreteStrategeA : Stratege
    {

        /// <summary>
        /// 具體算法
        /// </summary>
        public override void Algorithm()
        {
            // 策略A中實現的算法
        }
    }
    /// <summary>
    /// 具體策略 B,實現了一種具體算法
    /// </summary>
    public class ConcreteStrategeB : Stratege
    {

        /// <summary>
        /// 具體算法
        /// </summary>
        public override void Algorithm()
        {
            // 策略B中實現的算法
        }
    }


    /// <summary>
    /// Context 上下文,維護一個對Stratege對象的引用
    /// </summary>
    public class Context
    {
        private Stratege m_Stratege;

        /// <summary>
        /// 初始化上下文時,將具體策略傳入
        /// </summary>
        /// <param name="stratege"></param>
        public Context(Stratege stratege)
        {
            m_Stratege = stratege;
        }

        /// <summary>
        /// 根據具體策略對象,調用其算法
        /// </summary>
        public void ExecuteAlgorithm()
        {
            m_Stratege.Algorithm();
        }
    }

 

4. 模式總結

  4.1 優點

    4.1.1 策略模式是一種定義一系列算法的方法,從概念上來看,所有算法完成的都是相同的工作,只是實現不同,它可以以相同的方式調用所有的算法,減少了各種算法類與使用算法類之間的耦合。

    4.1.2 策略模式的Stratege類為Context定義了一系列的可供重用的算法或行為。繼承有助於析取出這些算法的公共功能。

    4.1.3 策略模式每個算法都有自己的類,可以通過自己的接口單獨測試。因而簡化了單元測試。

    4.1.4 策略模式將具體算法或行為封裝到Stratege類中,可以在使用這些類中消除條件分支(避免了不同行為堆砌到一個類中)。

  4.2 缺點

    將選擇具體策略的職責交給了客戶端,並轉給Context對象

  4.3 適用場景

    4.3.1 當實現某個功能需要有不同算法要求時

    4.3.2 不同時間應用不同的業務規則時

5. 實例:排序是我們經常接觸到的算法,實現對一個數組的排序有很多方法,即可以采用不同的策略。下面給出了排序功能的策略模式的解決方案。

  5.1 實現類圖

  

  5.2 代碼實現

    /// <summary>
    /// 排序算法策略
    /// </summary>
    public abstract class SortStratege
    {
        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public abstract int[] Sort(int[] array);
    }

    /// <summary>
    /// 冒泡排序
    /// </summary>
    public class BubbleSort : SortStratege
    {
        /// <summary>
        /// 冒泡排序算法(遞增排序)
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public override int[] Sort(int[] array)
        {
            // 實現冒泡排序算法
            for (int i = 0; i < array.Length; i++)
            {
                for (int j = i + 1; j < array.Length; j++)
                {
                    if (array[i] > array[j])
                    {
                        int temp = array[j];
                        array[j] = array[i];
                        array[i] = temp;
                    }
                }
            }

            return array;
        }
    }

    /// <summary>
    /// 插入排序
    /// </summary>
    public class InsertSort : SortStratege
    {

        /// <summary>
        /// 插入排序算法(遞增排序)
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public override int[] Sort(int[] array)
        {
            // 實現插入排序算法
            int temp;
            int i, j, n;
            n = array.Length;

            for (i = 1; i < n; i++)
            {
                temp = array[i];
                for (j = i; j > 0; j--)
                {
                    if (temp < array[j - 1])
                        array[j] = array[j - 1];
                    else
                        break;

                    array[j] = temp;
                }
            }
            return null;
        }
    }

    public class SortContext
    {
        private int[] m_Array;
        private SortStratege m_Stratege;

        /// <summary>
        /// 初始化時將要排序的數組和排序策略傳入給Context
        /// </summary>
        /// <param name="array"></param>
        /// <param name="stratege"></param>
        public SortContext(int[] array, SortStratege stratege)
        {
            m_Array = array;
            m_Stratege = stratege;
        }

        /// <summary>
        /// 調用排序算法
        /// </summary>
        /// <returns></returns>
        public int[] Sort()
        {
            int[] result = m_Stratege.Sort(this.m_Array);

            return result;
        }
    }

 

  5.3 客戶端代碼

    public class Program
    {
        public static void Main(Object[] args)
        {
            int[] array = new int[] { 12, 8, 9, 18, 22 };

            //使用冒泡排序算法進行排序
            SortStratege sortStratege = new BubbleSort();
            SortContext sorter = new SortContext(array, sortStratege);
            int[] result = sorter.Sort();

            //使用插入排序算法進行排序
            SortStratege sortStratege2 = new InsertSort();
            SortContext sorter2 = new SortContext(array, sortStratege2);
            int[] result2 = sorter.Sort();
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM