策略模式(Strategy): 策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是:“準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。 策略模式的角色: 1) ...
策略模式(Strategy):
策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是:“準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。
策略模式的角色:
1)環境類(Context):採用組合或聚合的方式維護一個對Strategy對象的引用。
2)抽象策略類(Strategy):定義所有支持的演算法的公共介面。Context使用這個介面來調用某ConcreteStrategy定義的演算法。
3)具體策略類(ConcreteStrategy):實現Strategy介面。
案例:
某商場銷售系統採用三種收費邏輯:正常收費;返現收費(滿300返20);打折收費(打8折)。
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 CashContext cashContext = new CashContext(new CashNormal()); 6 Console.WriteLine(cashContext.GetResult(200)); 7 CashContext cashContext2 = new CashContext(new CashRebate(0.8)); 8 Console.WriteLine(cashContext2.GetResult(200)); 9 CashContext cashContext3 = new CashContext(new CashReturn(300, 20)); 10 Console.WriteLine(cashContext3.GetResult(300)); 11 } 12 } 13 14 /// <summary> 15 /// 環境類Context 16 /// </summary> 17 public class CashContext 18 { 19 private CashSuper cs; 20 21 public CashContext(CashSuper cashSuper) 22 { 23 this.cs = cashSuper; 24 } 25 26 public double GetResult(double money) 27 { 28 if (cs != null) 29 { 30 return cs.AcceptCash(money); 31 } 32 return 0; 33 } 34 } 35 36 /// <summary> 37 /// 收費系統,相當於Strategy 38 /// </summary> 39 public interface CashSuper 40 { 41 double AcceptCash(double money); 42 } 43 44 /// <summary> 45 /// 正常收費 46 /// </summary> 47 public class CashNormal : CashSuper 48 { 49 public double AcceptCash(double money) 50 { 51 return money; 52 } 53 } 54 55 /// <summary> 56 /// 打折收費 57 /// </summary> 58 public class CashRebate : CashSuper 59 { 60 private double moneyRebate = 1d; 61 62 public CashRebate(double moneyRebate) 63 { 64 this.moneyRebate = moneyRebate; 65 } 66 67 public double AcceptCash(double money) 68 { 69 return money * moneyRebate; 70 } 71 } 72 73 /// <summary> 74 /// 返現收費 75 /// </summary> 76 public class CashReturn : CashSuper 77 { 78 private double moneyCondition = 0.0d; 79 private double moneyReturn = 0.0d; 80 81 public CashReturn(double moneyCondition, double moneyReturn) 82 { 83 this.moneyCondition = moneyCondition; 84 this.moneyReturn = moneyReturn; 85 } 86 87 public double AcceptCash(double money) 88 { 89 double result = money; 90 if (money >= moneyCondition) 91 result = money - Math.Floor(money / moneyCondition) * moneyReturn; 92 return result; 93 } 94 }
策略模式的優缺點:
優點:
1)策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的代碼轉移到父類裡面,從而避免重覆的代碼。
2)策略模式提供了可以替換繼承關係的辦法。繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。
3)使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。
缺點:
1)客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道所有的演算法或行為的情況。
2)策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴於環境的狀態保存到客戶端裡面,而將策略類設計成可共用的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用享元模式來減少對象的數量。
策略模式的應用場景:
1)一個系統需要動態地在幾種演算法中選擇一種時,可將每個演算法封裝到策略類中。
2)一個類定義了多種行為,並且這些行為在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。
3)系統中各演算法彼此完全獨立,且要求對客戶隱藏具體演算法的實現細節時。
4)系統要求使用演算法的客戶不應該知道其操作的數據時,可使用策略模式來隱藏與演算法相關的數據結構。
5)多個類只區別在表現行為不同,可以使用策略模式,在運行時動態選擇具體要執行的行為。
策略模式與工廠模式的區別?
從結構上看,策略模式和工廠模式都是子類繼承抽象父類,通過傳入參數到容器類(工廠模式的factory類,策略模式的Content類),選擇對應的類進行行為操作。但是我們都知道工廠模式是創建型設計模式,而策略模式則是行為型設計模式。那兩者到底有什麼區別呢?
1)工廠模式是用來創建對象,策略模式是讓一個對象在許多行為中選擇一種行為。
2)關註點不一樣,一個關註對象的創建,一個關註的是行為封裝。
3)解決不同的問題:工廠模式是創建型的設計模式,它接受指令,創建出符合要求的實例;它主要解決的是資源的統一分發,將對象的創建完全獨立出來,讓對象的創建和具體的使用客戶無關。主要應用在多資料庫選擇,類庫文件載入等。策略模式是為瞭解決的是策略的切換與擴展,更簡潔的說是定義策略族,分別封裝起來,讓他們之間可以相互替換,策略模式讓策略的變化獨立於使用策略的客戶。
4)工廠相當於黑盒子,策略相當於白盒子。
策略模式與橋接模式的區別?
在橋接模式中,Abstraction通過聚合的方式引用Implementor。策略模式中,Context也使用聚合的方式引用Strategy抽象介面。從兩者的結構圖可以看出,在這兩種模式中,都存在一個對象使用聚合的方式引用另一個對象的抽象介面的情況,而且該抽象介面的實現可以有多種並且可以替換。可以說兩者在表象上都是調用者與被調用者之間的解耦,以及抽象介面與實現的分離。但兩者存在一定的區別:
1)在形式上,在橋接模式中不僅Implementor具有變化(ConcreateImplementior),而且Abstraction也可以發生變化(RefinedAbstraction),而且兩者的變化是完全獨立的,RefinedAbstraction與ConcreateImplementior之間鬆散耦合,它們僅僅通過Abstraction與Implementor之間的關係聯繫起來。而在策略模式中,並不考慮Context的變化,只有演算法的可替代性。
2)在語意上,橋接模式強調Implementor介面僅提供基本操作,而Abstraction則基於這些基本操作定義更高層次的操作。而策略模式強調Strategy抽象介面的提供的是一種演算法,一般是無狀態、無數據的,而Context則簡單調用這些演算法完成其操作。
3)橋接模式中不僅定義Implementor的介面而且定義Abstraction的介面,Abstraction的介面不僅僅是為了與Implementor通信而存在的,這也反映了結構型模式的特點:通過繼承、聚合的方式組合類和對象以形成更大的結構。在策略模式中,Startegy和Context的介面都是兩者之間的協作介面,並不涉及到其它的功能介面,所以它是行為模式的一種。行為模式的主要特點就是處理的是對象之間的通信方式,往往是通過引入中介者對象將通信雙方解耦,在這裡實際上就是將Context與實際的演算法提供者解耦。
所以相對策略模式,橋接模式要表達的內容要更多,結構也更加複雜。橋接模式表達的主要意義其實是介面隔離的原則,即把本質上並不內聚的兩種體系區別開來,使得它們可以鬆散的組合,而策略在解耦上還僅僅是某一個演算法的層次,沒有到體系這一層次。從結構圖中可以看到,策略的結構是包容在橋接結構中的,橋接中必然存在著策略模式,Abstraction與Implementor之間就可以認為是策略模式,但是橋接模式一般Implementor將提供一系列的成體系的操作,而且Implementor是具有狀態和數據的靜態結構。而且橋接模式Abstraction也可以獨立變化。
參考:https://blog.csdn.net/donnie88888888/article/details/52751328
https://blog.csdn.net/basycia/article/details/50478245
http://www.blogjava.net/wangle/archive/2007/04/25/113545.html