文章目錄
策略模式:
The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。)
Context(應用情境):
需要使用ConcreteStrategy提供的演算法。
內部維護一個Strategy的執行個體。
負責動態設定運行時Strategy具體的實現演算法。
負責跟Strategy之間的互動和資料傳遞。
Strategy(抽象策略類):
定義了一個公用介面,各種不同的演算法以不同的方式實現這個介面,Context使用這個介面調用不同的演算法,一般使用介面或抽象類別實現。
ConcreteStrategy(具體策略類):
實現了Strategy定義的介面,提供具體的演算法實現。
廢話少說,到.NET類庫中找找策略模式
ArrayList類肯定都會用過吧,那麼它的Sort方法想必大家也一定不陌生了。Sort方法的定義如下:
public virtual void Sort (IComparer comparer)
可以看到Sort方法接收一個IComparer類型的參數,那麼這個IComparer介面是做什麼用的呢?下面我們看一段程式,下面的程式碼範例示範如何使用預設比較子和一個反轉排序次序的自訂比較子,對ArrayList 中的值進行排序:
using System;
using System.Collections;
public class SamplesArrayList
{
public class myReverserClass : IComparer
{
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
int IComparer.Compare(Object x, Object y)
{
return ((new CaseInsensitiveComparer()).Compare(y, x));
}
}
public static void Main()
{
// Creates and initializes a new ArrayList.
ArrayList myAL = new ArrayList();
myAL.Add("The");
myAL.Add("quick");
myAL.Add("brown");
myAL.Add("fox");
myAL.Add("jumps");
myAL.Add("over");
myAL.Add("the");
myAL.Add("lazy");
myAL.Add("dog");
// Displays the values of the ArrayList.
Console.WriteLine("The ArrayList initially contains the following values:");
PrintIndexAndValues(myAL);
// Sorts the values of the ArrayList using the default comparer.
myAL.Sort();
Console.WriteLine("After sorting with the default comparer:");
PrintIndexAndValues(myAL);
// Sorts the values of the ArrayList using the reverse case-insensitive comparer.
IComparer myComparer = new myReverserClass();
myAL.Sort(myComparer);
Console.WriteLine("After sorting with the reverse case-insensitive comparer:");
PrintIndexAndValues(myAL);
}
public static void PrintIndexAndValues(IEnumerable myList)
{
int i = 0;
foreach (Object obj in myList)
Console.WriteLine("\t[{0}]:\t{1}", i++, obj);
Console.WriteLine();
}
}
/*
This code produces the following output.
The ArrayList initially contains the following values:
[0]: The
[1]: quick
[2]: brown
[3]: fox
[4]: jumps
[5]: over
[6]: the
[7]: lazy
[8]: dog
After sorting with the default comparer:
[0]: brown
[1]: dog
[2]: fox
[3]: jumps
[4]: lazy
[5]: over
[6]: quick
[7]: the
[8]: The
After sorting with the reverse case-insensitive comparer:
[0]: the
[1]: The
[2]: quick
[3]: over
[4]: lazy
[5]: jumps
[6]: fox
[7]: dog
[8]: brown
*/
怎麼樣,大家看出來了吧,其實在這段代碼裡,ArrayList相當於Strategy模式中的Context(應用情境)部分,而IComparer相當於Strategy(抽象策略類)部分,myReverserClass相當於ConcreteStrategy(具體策略類)部分。我們這裡拋開myReverserClass類的Compare方法如何具體實現不談,我們只要知道這是一個具體策略類,它提供了應用情境需要的具體演算法,它實現了抽象策略類介面,而應用情境通過抽象策略類動態調用到了具體策略類中的演算法。哈!所以這是一個十分典型的Strategy模式的應用。
基於這個符合Strategy模式的結構,我們還可以提供很多種自訂的具體策略類的實現,只要這些類實現了IComparer介面,就可以在運行時動態設定給ArrayList類的Sort方法,在Sort方法中會根據具體策略類實現的比較演算法規則來對ArrayList中的資料進行排序。
策略模式應用情境和優缺點
上面我們已經看過了Strategy模式的詳細介紹,下面我們再來簡單說說這個模式的優缺點吧!怎麼說呢,人無完人,設計模式也不是萬能的,每一個模式都有它的使命,也就是說只有在特定的情境下才能發揮其功效。我們要使用好模式,就必須熟知各個模式的應用情境。
對於Strategy模式來說,主要有這些應用情境:
1、 多個類只區別在表現行為不同,可以使用Strategy模式,在運行時動態選擇具體要執行的行為。(例如FlyBehavior和QuackBehavior)
2、 需要在不同情況下使用不同的策略(演算法),或者策略還可能在未來用其它方式來實現。(例如FlyBehavior和QuackBehavior的具體實現可任意變化或擴充)
3、 對客戶(Duck)隱藏具體策略(演算法)的實現細節,彼此完全獨立。
對於Strategy模式來說,主要有如下優點:
1、 提供了一種替代繼承的方法,而且既保持了繼承的優點(代碼重用)還比繼承更靈活(演算法獨立,可以任意擴充)。
2、 避免程式中使用多重條件轉移語句,使系統更靈活,並易於擴充。
3、 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
對於Strategy模式來說,主要有如下缺點:
1、 因為每個具體策略類都會產生一個新類,所以會增加系統需要維護的類的數量。
最後一個設計原則
關於Strategy模式的故事講到這裡,應該基本OK啦!下面我們再聊些更高層次的東西。什麼是更高層次的東西?嘿!當然是設計原則了!在前面總結Strategy模式的優點的時候我們提到過,Strategy模式不僅保留了繼承的優點,而且還提供了更靈活的擴充能力。為什麼會這樣呢?Strategy模式是怎麼做到這一點的呢?哈!這是因為它“上面有人”啊!誰啊?它就是我們下面要介紹的重量級設計原則:
Favor composition over inheritance.(優先使用對象組合,而非類繼承)
關於組合和繼承,我們只要這樣來理解即可:組合是一種“HAS-A”關係,而繼承是一種“IS-A”關係。很明顯“HAS-A”要比“IS-A”更靈活一些。也就是說在建立系統的時候,我們應該優先使用對象組合,因為它不僅可以給你提供更多靈活性和擴充性,而且還使你可以在運行時改變行為(組合不同的對象),這簡直是酷斃了!但是也不是說繼承就是不能用,只是說應該把繼承應用在相對更穩定,幾乎沒有變化的地方,例如前面的Duck類裡的Swim()方法,因為可以肯定所有鴨子一定都會遊泳,所以就沒有必要給這個行為提供基於Strategy模式的實現方式,因為那樣做除了是程式更複雜以外,沒有什麼意義。
參考:http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html