[.net 物件導向程式設計深入](26)實戰設計模式——策略模式 Strategy (行為型)

yubinfeng發表於2017-03-13

[.net 物件導向程式設計深入](26)實戰設計模式——策略模式 Strategy (行為型)

1,策略模式定義

策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。

策略模式的組成: 

—抽象策略角色: 策略類,通常由一個介面或者抽象類實現。 
—具體策略角色:包裝了相關的演算法和行為。 
—環境角色:持有一個策略類的引用,最終給客戶端呼叫。 

2,策略模式適場景

 (1)多個相關的類中,僅行為不同,即一個系統中需要在幾個不同的演算法中選擇時。比如中出行中,我們選擇交通方式火車、飛機、自行車、汽車等。

(2)一個演算法的不同變體時。比如一個收取暖費的演算法,不同的收費方式如按房屋面積、按供熱焦耳量、按面積和熱量混合法等 。

(3)不想暴露演算法給使用者。比如,有一個複雜演算法或演算法中有相對應的資料結構不想讓使用者知道。

(4)一個行為中有多個條件時。比如,有多個條件語句,而且實現比較複雜或比較長時,使用策略模式,除了結構清晰外,維護某一分支也比較方便。

3,策略模式優點 

(1)抽象策略類和具體策略角色為環境類定義了一系列可以重用的演算法或行為,並且繼承有助於取出共用部分的演算法。

(2)提供了可以替換繼承關係的辦法。可以建立一個環境類的子類,裡面封裝不同的行為,通過環境類來驅動策略。但這樣也會導致環境類中的行為包含了具體實現,使用程式難以理解,難以維護。

(3)消除了複雜的IF..ELSE。含有許多複雜條件語句的程式碼可以使用策略模式來使邏輯更加清晰,易於維護。

(4)實了具有相同型別的多個行業的切換。讓使用者在多個策略中切換行為。

4,策略模式缺點

(1)需要事先知道所有策略類行為有何不同,才能讓使用者很好的選擇。容易向使用者暴露策略中的各個行為。

(2)環境類和策略類之間產生通訊開銷。

(3)需要建立很多策略類。後面會說到享元模式,一定程度上減少類。

5,策略模式應用

(1)華山論劍

      還是以熟悉的華山論劍為例,比賽方式(也就是三個具體策略類)有“比外功、比內功、比招式”,場景為“華山”(也就是場景類HuaShan),開始比賽了,主持人事先知道這幾種比賽方式(也就是具體策略類),主持人(也就是具體使用者)讓依次以這幾種方式進行。

      先看一下UML類圖(在VS中使用類圖,可以參考我前面的文章:在Visual Studio 2013/2015中設計UML類圖

    

下面是具體程式碼:

 抽象策略類 LunJian

public abstract class LunJian
{
    public abstract void BiSai();    
}

具體策略類 WaiGong NeiGong ZhaoShi

public class WaiGong : LunJian
{
    public override void BiSai()
    {
        Console.WriteLine("外功比試開始了!");
    }
}
public class NeiGong : LunJian
{
    public override void BiSai()
    {    
        Console.WriteLine("內功比試開始了!");
    }
}
public class ZhaoShi : LunJian
{
    public override void BiSai()
    {
        Console.WriteLine("招式比試開始了!");
    }
}

場景類(也就是策略上下文 ) HuaShan

public class HuaShan
{
     LunJian lunJian=null;

    public void SetLunJian(LunJian lunJian)
    {
        this.lunJian = lunJian;
    }

    public void BiShi()
    {
        this.lunJian.BiSai();
    }
}

使用者,就是控制檯應用程式

class Program
    {
        static void Main(string[] args)
        {
            HuaShan huanShan = new HuaShan();

            huanShan.SetLunJian(new WaiGong());
            huanShan.BiShi();
           
            huanShan.SetLunJian(new NeiGong());
            huanShan.BiShi();

            huanShan.SetLunJian(new ZhaoShi());
            huanShan.BiShi();

            Console.ReadLine();
        }
    }

依次給出三種比試方式策略,執行結果如下:

(2)華山論劍升級版

上面的示例比較簡單,假如我們比試開始的時候,還需要點名兩個比賽選手,這就需要在具體策略類的方法中增加引數。我們增加BiShi()方法引數,改進後程式碼如下:

  抽象策略類 LunJian

public abstract class LunJian
{
    public abstract void BiSai(string player1,string player2);
    
}

  具體策略類 WaiGong NeiGong ZhaoShi

public class WaiGong : LunJian
{
    public override void BiSai(string player1,string player2)
    {
        Console.WriteLine("外功比試開始了!"+string.Format(" {0} 和 {1} 出場",player1,player2));
    }
}
public class NeiGong : LunJian
{
    public override void BiSai(string player1, string player2)
    {    
        Console.WriteLine("內功比試開始了!" + string.Format(" {0} 和 {1} 出場", player1, player2));
    }
}
public class ZhaoShi : LunJian
{
    public override void BiSai(string player1, string player2)
    {
        Console.WriteLine("招式比試開始了!" + string.Format(" {0} 和 {1} 出場", player1, player2));
    }
}

  場景類(也就是策略上下文 ) HuaShan

public class HuaShan
{
     LunJian lunJian=null;

    public void SetLunJian(LunJian lunJian)
    {
        this.lunJian = lunJian;
    }

    public void BiShi(string player1,string player2)
    {
        this.lunJian.BiSai(player1,player2);
    }
}

  使用者,就是控制檯應用程式

    class Program
    {
        static void Main(string[] args)
        {
            HuaShan huanShan = new HuaShan();

            huanShan.SetLunJian(new WaiGong());
            huanShan.BiShi("黃藥師","歐陽鋒");
           
            huanShan.SetLunJian(new NeiGong());
            huanShan.BiShi("洪七公","一燈大師");

            huanShan.SetLunJian(new ZhaoShi());
            huanShan.BiShi("歐陽鋒","洪七公");

            Console.ReadLine();
        }
    }

執行結果:

華山論劍的業務肯定比這個要複雜,上面的出場人不同,比賽方式不同,甚至還其他不同的規則出現。

如果我們不使用策略模式,而通過傳統的if...else來寫,不但要寫很長的程式碼,還需要條件語句多次巢狀。

最主要的是程式碼的可讀性較差,而且難以再解。

6,總結 

(1)策略模式是一個比較容易理解和使用的設計模式,策略模式是對演算法的封裝,它把演算法的責任和演算法本身分割開,委派給不同的物件管理。策略模式通常把一個系列的演算法封裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是“準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。
(2)在策略模式中,應當由客戶端自己決定在什麼情況下使用什麼具體策略角色。

(3)策略模式僅僅封裝演算法,提供新演算法插入到已有系統中,以及老演算法從系統中“退休”的方便,策略模式並不決定在何時使用何種演算法,演算法的選擇由客戶端來決定。這在一定程度上提高了系統的靈活性,但是客戶端需要理解所有具體策略類之間的區別,以便選擇合適的演算法,這也是策略模式的缺點之一,在一定程度上增加了客戶端的使用難度。

7.例項原始碼

https://github.com/yubinfeng/BlogExamples.git

==============================================================================================

返回目錄

<如果對你有幫助,記得點一下推薦哦,如有有不明白或錯誤之處,請多交流>

<對本系列文章閱讀有困難的朋友,請先看 《.net 物件導向程式設計基礎》 和 《.net 物件導向程式設計進階》 >

<轉載宣告:技術需要共享精神,歡迎轉載本部落格中的文章,但請註明版權及URL>

.NET 技術交流群:467189533 H.NET 技術交流群

==============================================================================================

相關文章