華文網

實戰設計模式——策略模式 Strategy

[.net 物件導向程式設計深入](21)實戰設計模式——策略模式 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="" 物件導向程式設計進階》="">

(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="" 物件導向程式設計進階》="">