一、策略模式定義:
策略模式(Strategy)定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化不會影響到使用算法的客戶。
分析:
封裝的算法本身是一種策略,重要的是這些算法隨時可能互相替換的,這就是變化點,而封裝變化點是面向對象的一種重要的思維方式。策略模式定義的這些算法完成的都是相同的工作,只是實現不同,它可以以相同的方式調用所有的算法,減少了各種算法類與使用算法類之間的耦合。
二、UML類圖:
三、策略模式的基本代碼:
class PRogram { static void Main(string[] args) { Contex context; context = new Contex(new ConcreteStrategyA()); context.ContexInterface(); context = new Contex(new ConcreteStrategyB()); context.ContexInterface(); Console.Read(); } } abstract class Strategy { public abstract void AlgorithmInterface(); } class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法A實現"); } } class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法B實現"); } } class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法C實現"); } } class Contex { Strategy strategy; public Contex(Strategy strategy) { this.strategy = strategy; } public void ContexInterface() { strategy.AlgorithmInterface(); } }
四、舉例說明:
功能:在一家商場有三種銷售方式:正常價格、打折銷售和返現銷售,設計一個收銀軟件,要求能滿足上述的銷售方式。本例采用策略模式,將三種銷售方式封裝起來。
基本代碼:
abstract class CashSuper { public abstract double acceptCash(double money); } //正常價格 class CashNormal : CashSuper { public override double acceptCash(double money) { return money; } } //打折策略 class CashRebate : CashSuper { private double moneyRebate = 1d; public CashRebate(string moneyRebate) { this.moneyRebate = double.Parse(moneyRebate); } public override double acceptCash(double money) { return money * moneyRebate; } } //返現策略 class CashReturn : CashSuper { private double moneyCondition = 0d; private double moneyReturn = 0d; public CashReturn(string moneyCondition, string moneyReturn) { this.moneyCondition = double.Parse(moneyCondition); this.moneyReturn = double.Parse(moneyReturn); } public override double acceptCash(double money) { double result = money; if (money >= moneyCondition) { result = money - Math.Floor(money / moneyCondition) * moneyReturn; } return result; } } class CashContext { private CashSuper cashSuper; public CashContext(CashSuper cashSuper) { this.cashSuper = cashSuper; } public double GetResult(double money) { return cashSuper.acceptCash(money); } }
調用方式:
cashContext = new CashContext(new CashRebate("0.8"));totalPrices = cashContext.GetResult(Convert.ToDouble(this.tbPrice.Text) * Convert.ToDouble(this.tbNumber.Text));
五、策略模式和簡單工廠模式結合:
結合后,實例化具體策略的過程由客戶端轉移到Context類中。修改后的CashContext:
class CashContext { CashSuper cs = null; public CashContext(string type) { switch (type) { case "正常收費": CashNormal cs0 = new CashNormal(); cs = cs0; break; case "滿300返100": CashReturn cs1 = new CashReturn("300", "100"); break; case "打八折": CashRebate cs2 = new CashRebate("0.8"); cs = cs2; break; } } public double GetResult(double money) { return cs.acceptCash(money); } }
六、適用場景:
1、在一個系統(tǒng)內有很多類,它們完成相同的功能僅在行為上有所區(qū)別,策略模式可以動態(tài)地選擇一種行為。
2、一個系統(tǒng)的算法使用的數據不讓客戶端獲取。策略模式可以避免客戶端涉及到一些復雜的或特別的數據。
3、如果一個對象有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。此時,使用策略模式,把這些行為轉移到相應的具體策略類里面,就可以避免使用難以維護的多重條件選擇語句,并體現面向對象設計的概念。
4、 一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種。那么這些算法可以包裝到一個個的具體算法類里面,而這些具體算法類都是一個抽象算法類的子類。換言之,這些具體算法類均有統(tǒng)一的接口,由于多態(tài)性原則,客戶端可以選擇使用任何一個具體算法類,并只持有一個數據類型是抽象算法類的對象。
七、策略模式優(yōu)缺點:
優(yōu)點:
1、 簡化了單元測試,因為每個算法都有自己的類,可以通過自己的接口單獨測試。
2、 定義了一系列的可供重用的算法或行為。繼承有助于析取出這些算法中的公共功能。
3、 遵守大部分GRasp原則和常用設計原則,高內聚、低偶合。
缺點:
1. 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時選擇恰當的算法類。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
2. 策略模式造成很多的策略類。有時候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面,而將策略類設計成可共享的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用享元模式來減少對象的數量。
新聞熱點
疑難解答