文章目錄
- 什麼是策略模式
- 策略模式的結構
- 策略模式的優缺點
- 策略模式的代碼執行個體
- 策略模式和簡單工廠的區別
什麼是策略模式
策略模式(Strategy Pattern):定義了演算法家族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化,不會影響到使用演算法的客戶。
策略模式是一種定義了一系列演算法的方法,從概念上來看,所以得這些演算法完成的都是相同的工作,只是實現不同,它可以以相同的方式調用所有的演算法,減少了各種演算法類與使用演算法類之間的耦合。
策略模式的結構
我們先觀察策略模式(Strategy Pattern)的UML類圖:
根據前面的類圖我們可以知道策略模式由下面的幾個部分組成:
- 抽象策略類:所以策略子類的通用介面,通常由一個抽象類別和介面來實現。
- 具體策略類:實現了抽象策略類,封裝的相關的演算法和行為。
- Context類:供客戶代碼調用,持有一個抽象策略類的引用,根據用戶端不同的調用,返回不同的具體策略執行個體。
策略模式的優缺點
策略模式的優點:
- 提供了一種替代繼承的方法,而且既保持了繼承的優點(代碼重用)還比繼承更靈活(演算法獨立,可以任意擴充)。
- 策略模式的Strategy類層次為Context定義了一系列可供重用的演算法或行為。繼承有助於析取出這些演算法中的公用功能。
- 當不同的行為堆砌在一個類中時,就很難避免使用條件陳述式來選擇合適的行為。將這些行為封裝在一個個獨立的Strategy類中,可以再使用這些行為的類中消除條件陳述式。
- 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
- 策略模式簡化了單元測試,因為每個演算法都有自己的類,可以通過自己的介面單獨測試。
策略模式的缺點:
- 因為每個具體策略類都會產生一個新類,所以會增加系統需要維護的類的數量。
- 與簡單工廠結合後還需要修改switch分支語句。
策略模式的代碼執行個體
根據商場打折、促銷等,演算法需要經常性的變動的情境來提供一個策略模式實現的一個收費程式。
首先定義一個結算的抽象類別(介面):
1 /// <summary>2 /// 現金收費抽象類別3 /// </summary>4 abstract class CashSuper5 {6 //現金收取超類的抽象方法,收取現金,參數為原價,返回當前價。7 public abstract double acceptCash(double money);8 }
然後根據打折、促銷等不同的活動實現具體收費功能的子類
1 /// <summary> 2 /// 正常收費子類 3 /// </summary> 4 class CashNormal:CashSuper 5 { 6 public override double acceptCash(double money) 7 { 8 return money; 9 }10 }11 12 /// <summary>13 /// 打摺子類14 /// </summary>15 class CashRebate:CashSuper16 {17 private double moneyRebate = 1d;18 public CashRebate(string moneyRebate)19 {20 this.moneyRebate = double.Parse(moneyRebate);21 }22 23 public override double acceptCash(double money)24 {25 return money * moneyRebate;26 }27 }28 29 /// <summary>30 /// 返利子類31 /// </summary>32 class CashReturn:CashSuper33 {34 private double moneyCondition = 0.0d;35 private double moneyReturn = 0.0d;36 37 /// <summary>38 /// 返利子類構造方法39 /// </summary>40 /// <param name="moneyCondition">返利標準</param>41 /// <param name="moneyReturn">返利值</param>42 public CashReturn(string moneyCondition, string moneyReturn)43 {44 this.moneyCondition = double.Parse(moneyCondition);45 this.moneyReturn = double.Parse(moneyReturn);46 }47 48 public override double acceptCash(double money)49 {50 double result = money;51 52 if (money >= moneyCondition)53 result = money - Math.Floor(money / moneyCondition) * moneyReturn;54 55 return result;56 }57 }
最後建立的是提供給用戶端調用的Context類
1 class CashContext 2 { 3 CashSuper cs; 4 5 public CashContext(string type) 6 { 7 //簡單工廠建構函式,克服用戶端需要知道所以演算法子類的缺點(封裝了變化) 8 switch (type) 9 {10 case "正常收費":11 cs = new CashNormal();12 break;13 case "滿300返100":14 cs = new CashReturn("300", "100");15 break;16 case "打8折":17 cs = new CashRebate("0.8");18 break;19 }20 }21 22 //和簡單工廠的不同之處23 public double GetResult(double money)24 {25 return cs.acceptCash(money);26 }27 }
在基本的策略模式中,選擇所用具體實現的職責由用戶端對象承擔,並轉給策略模式的Context對象。這本身並沒有解除用戶端需要判斷選擇的壓力,而策略模式與簡單工廠結合後,選擇具體實現的職責也可以由Context承擔,這就最大化減輕了用戶端的職責。
客戶代碼調用,編譯運行:
1 CashContext csuper = new CashContext(cmbDiscount.SelectedItem.ToString());2 double totalPrices = 0d;3 totalPrices = csuper.GetResult(double.Parse(this.txtPrice.Text) * double.Parse(this.txtNumber.Text));4 5 this.lbxResult.Items.Add("單價:" + this.txtPrice.Text + " 數量:" + this.txtNumber.Text + " " + cmbDiscount.SelectedItem + " " + "合計" + totalPrices.ToString());6 7 total = total + totalPrices;8 this.lblAmount.Text = total.ToString();
策略模式和簡單工廠的區別
通過對比簡單工廠和策略模式的UML類圖我們可以發現二者結構比較相似:
我們可以發現使用原則模式實現的都可以使用簡單工廠來實現,二者都是通過使用繼承以多態的形式來實現的。在產品構造多次重疊,並且在不同時刻應用不同的規則(演算法)時使用原則模式比較合適。我們可以發現簡單工廠只是通過一個靜態類方法來建立不同的子類,但是在策略模式中除了通過多態建立不同的演算法子類,還有一個調用子類樣本函數的一個成員方法(Context類中),所以在用戶端中我們只需要擷取一個Context執行個體時候,然後通過直接調用它的執行個體方法來間接調用子類的成員方法就可以了(建構函式使用簡單工廠來實現);但是在簡單工廠中我們除了通過調用工廠類的靜態方法擷取產品子類的執行個體,還要直接調用子類的成員方法。
猛擊下載:範例程式碼
參考資料:《大話設計模式》
作者:晴天豬
出處:http://www.cnblogs.com/IPrograming
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。