1,策略模式定義

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

策略模式的組成: 

—抽象策略角色: 策略類,通常由一個接口或者抽象類實(shí)現(xiàn)。 

—具體策略角色:包裝了相關(guān)的算法和行為。 

—環(huán)境角色:持有一個策略類的引用,最終給客戶端調(diào)用。 

2,策略模式適場景

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

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

(3)不想暴露算法給使用者。比如,有一個復(fù)雜算法或算法中有相對應(yīng)的數(shù)據(jù)結(jié)構(gòu)不想讓使用者知道。

(4)一個行為中有多個條件時。比如,有多個條件語句,而且實(shí)現(xiàn)比較復(fù)雜或比較長時,使用策略模式,除了結(jié)構(gòu)清晰外,維護(hù)某一分支也比較方便。

3,策略模式優(yōu)點(diǎn) 

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

(2)提供了可以替換繼承關(guān)系的辦法。可以創(chuàng)建一個環(huán)境類的子類,里面封裝不同的行為,通過環(huán)境類來驅(qū)動策略。但這樣也會導(dǎo)致環(huán)境類中的行為包含了具體實(shí)現(xiàn),使用程序難以理解,難以維護(hù)。

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

(4)實(shí)了具有相同類型的多個行業(yè)的切換。讓用戶在多個策略中切換行為。

4,策略模式缺點(diǎn)

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

(2)環(huán)境類和策略類之間產(chǎn)生通信開銷。

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

5,策略模式應(yīng)用

(1)華山論劍

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

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

    大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

下面是具體代碼:

 抽象策略類 LunJian

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

具體策略類 WaiGong NeiGong ZhaoShi

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

public class NeiGong : LunJian
{    public override void BiSai()
    {    
        Console.WriteLine("內(nèi)功比試開始了!");
    }
}

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

public class HuaShan
{
     LunJian lunJian=null;    public void SetLunJian(LunJian lunJian)
    {        this.lunJian = lunJian;
    }    public void BiShi()
    {        this.lunJian.BiSai();
    }
}

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

使用者,就是控制臺應(yīng)用程序

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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();
        }
    }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

依次給出三種比試方式策略,運(yùn)行結(jié)果如下:

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

(2)華山論劍升級版

上面的示例比較簡單,假如我們比試開始的時候,還需要點(diǎn)名兩個比賽選手,這就需要在具體策略類的方法中增加參數(shù)。我們增加BiShi()方法參數(shù),改進(jìn)后代碼如下:

  抽象策略類 LunJian

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

  具體策略類 WaiGong NeiGong ZhaoShi

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

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);
    }
}

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

  使用者,就是控制臺應(yīng)用程序

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

    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();
        }
    }

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

運(yùn)行結(jié)果:

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計(jì)算培訓(xùn),高端軟件開發(fā)培訓(xùn),項(xiàng)目經(jīng)理培訓(xùn)

華山論劍的業(yè)務(wù)肯定比這個要復(fù)雜,上面的出場人不同,比賽方式不同,甚至還其他不同的規(guī)則出現(xiàn)。

如果我們不使用策略模式,而通過傳統(tǒng)的if...else來寫,不但要寫很長的代碼,還需要條件語句多次嵌套。

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

6,總結(jié) 

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

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