1、策略模式定義:算法
策略模式(Strategy)定義了算法家族,分別封裝起來,讓它們之間能夠互相替換,此模式讓算法的變化不會影響到使用算法的客戶。ide
分析:單元測試
封裝的算法自己是一種策略,重要的是這些算法隨時可能互相替換的,這就是變化點,而封裝變化點是面向對象的一種重要的思惟方式。策略模式定義的這些算法完成的都是相同的工做,只是實現不一樣,它能夠以相同的方式調用全部的算法,減小了各類算法類與使用算法類之間的耦合。 測試
2、UML類圖:this
3、策略模式的基本代碼: spa
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(); } }
4、舉例說明: 設計
功能:在一家商場有三種銷售方式:正常價格、打折銷售和返現銷售,設計一個收銀軟件,要求能知足上述的銷售方式。本例採用策略模式,將三種銷售方式封裝起來。code
基本代碼: orm
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));
5、策略模式和簡單工廠模式結合:
結合後,實例化具體策略的過程由客戶端轉移到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); } }
6、適用場景:
一、在一個系統內有不少類,它們完成相同的功能僅在行爲上有所區別,策略模式能夠動態地選擇一種行爲。
二、一個系統的算法使用的數據不讓客戶端獲取。策略模式能夠避免客戶端涉及到一些複雜的或特別的數據。
三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。此時,使用策略模式,把這些行爲轉移到相應的具體策略類裏面,就能夠避免使用難以維護的多重條件選擇語句,並體現面向對象設計的概念。
四、 一個系統須要動態地在幾種算法中選擇一種。那麼這些算法能夠包裝到一個個的具體算法類裏面,而這些具體算法類都是一個抽象算法類的子類。換言之,這些具體算法類均有統一的接口,因爲多態性原則,客戶端能夠選擇使用任何一個具體算法類,並只持有一個數據類型是抽象算法類的對象。
7、策略模式優缺點:
優勢:
一、 簡化了單元測試,由於每一個算法都有本身的類,能夠經過本身的接口單獨測試。
二、 定義了一系列的可供重用的算法或行爲。繼承有助於析取出這些算法中的公共功能。
三、 遵照大部分GRASP原則和經常使用設計原則,高內聚、低偶合。
缺點:
1. 客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道全部的算法或行爲的狀況。
2. 策略模式形成不少的策略類。有時候能夠經過把依賴於環境的狀態保存到客戶端裏面,而將策略類設計成可共享的,這樣策略類實例能夠被不一樣客戶端使用。換言之,可使用享元模式來減小對象的數量。