策略模式的結構算法
這個模式涉及到三個角色:數組
環境(Context)角色:持有一個 Strategy 類的引用。
抽象策略(Strategy)角色:這是一個抽象角色,一般由一個接口或抽象類實現。此角色給出全部的具體策略類所需的接口。
具體策略(ConcreteStrategy)角色:包裝了相關的算法或行爲。ide
上篇博文寫的CashSuper 就是抽象策略,而正常收費 CashNormal、打折收費 CashRebate 和返利收費 CashReturn 就是三個具體策略,也就是策略模式中說的具體算法。this
附上上篇博文的部分代碼spa
//正常消費,繼承CashSuper class CashNormal:CashSuper { public override double acceptCash(double money) { return money; } }
//打折收費消費,繼承CashSuper class CashRebate:CashSuper { private double moneyRebate = 1d; //初始化時,必須要輸入折扣率,如八折,就是0,8 public CashRebate(string moneyRebate) { //界面向類傳值 this.moneyRebate = double.Parse(moneyRebate); } public override double acceptCash(double money) { return money * moneyRebate; } }
//返利收費 class CashReturn:CashSuper { private double moneyCondition = 0.0d; private double moneyReturn = 0.0d; //初始化時必需要輸入返利條件和返利值,好比滿300返100 //則moneyCondition爲300,moneyReturn爲100 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; } }
//現金收取父類 abstract class CashSuper { //抽象方法:收取現金,參數爲原價,返回爲當前價 public abstract double acceptCash(double money); }
加入的策略模式(這裏能夠棄用工廠模式了).net
1 namespace ExtendDiscountOfStrategyPattern 2 { 3 class CashContext 4 { 5 //聲明一個現金收費父類對象 6 private CashSuper cs; 7 8 //設置策略行爲,參數爲具體的現金收費子類(正常,打折或返利) 9 public void setBehavior(CashSuper csuper) 10 { 11 this.cs = csuper; 12 } 13 14 //獲得現金促銷計算結果(利用了多態機制,不一樣的策略行爲致使不一樣的結果) 15 public double GetResult(double money) 16 { 17 return cs.acceptCash(money); 18 } 19 } 20 }
可是程序仍是少不了switch...case語句,code
核心代碼(v1.3)orm
1 //聲明一個double變量total來計算總計 2 double total = 0.0d; 3 private void btnConfirm_Click(object sender, EventArgs e) 4 { 5 //聲明一個double變量totalPrices 6 double totalPrices = 0d; 7 //策略模式 8 CashContext cc = new CashContext(); 9 switch (cbxType.SelectedItem.ToString()) 10 { 11 case "正常消費": 12 cc.setBehavior(new CashNormal()); 13 break; 14 case "滿300返100": 15 cc.setBehavior(new CashReturn("300", "100")); 16 break; 17 case "打8折": 18 cc.setBehavior(new CashRebate("0.8")); 19 break; 20 case "打7折": 21 cc.setBehavior(new CashRebate("0.7")); 22 break; 23 case "打5折": 24 cc.setBehavior(new CashRebate("0.5")); 25 break; 26 } 27 totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); 28 //將每一個商品合計計入總計 29 total = total + totalPrices; 30 //在列表框中顯示信息 31 lbxList.Items.Add("單價:" + txtPrice.Text + " 數量:" + txtNum.Text + " 合計:" + totalPrices.ToString()); 32 //在lblTotalShow標籤上顯示總計數 33 lblTotalShow.Text = total.ToString(); 34 }
最初的策略模式是有缺點的,客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶
端知道全部的算法或行爲的狀況最初的策略模式是有缺點的,客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道全部的算法或行爲的狀況。xml
去掉switch...case語句!!!——(本案例採用簡單的.net技術:反射)對象
關鍵的操做代碼爲:Assembly.Load(" 程序集名稱").CreateInstance(" 名稱空間.類名稱");
客戶端代碼(v1.4)
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 //add 11 using CCWin; 12 using System.Data.SqlClient; 13 14 namespace ExtendDiscountOfStrategyPatternWithReflection 15 { 16 using System.Reflection; 17 18 public partial class frmMain :Skin_Metro 19 { 20 21 DataSet ds; //用於存放配置文件信息 22 23 public frmMain() 24 { 25 InitializeComponent(); 26 } 27 28 //聲明一個double變量total來計算總計 29 double total = 0.0d; 30 private void btnConfirm_Click(object sender, EventArgs e) 31 { 32 //聲明一個double變量totalPrices 33 double totalPrices = 0d; 34 //策略模式 35 CashContext cc = new CashContext(); 36 //根據用戶的選項,查詢用戶選擇項的相關行 37 DataRow dr = ((DataRow[])ds.Tables[0].Select("name='" + cbxType.SelectedItem.ToString() + "'"))[0]; 38 //聲明一個參數的對象數組 39 object[] args = null; 40 //如有參數,則將其分割成字符串數組,用於實例化時所用的參數 41 if (dr["para"].ToString() != "") 42 { 43 args = dr["para"].ToString().Split(','); 44 } 45 //經過反射實例化出相應的算法對象 46 cc.setBehavior((CashSuper)Assembly.Load("ExtendDiscountOfStrategyPatternWithReflection"). 47 CreateInstance("ExtendDiscountOfStrategyPatternWithReflection." + dr["class"].ToString(), false, 48 BindingFlags.Default, null, args, null, null)); 49 50 totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); 51 //將每一個商品合計計入總計 52 total = total + totalPrices; 53 //在列表框中顯示信息 54 lbxList.Items.Add("單價:" + txtPrice.Text + " 數量:" + txtNum.Text + " 合計:" + totalPrices.ToString()); 55 //在lblTotalShow標籤上顯示總計數 56 lblTotalShow.Text = total.ToString(); 57 } 58 59 private void btnReset_Click(object sender, EventArgs e) 60 { 61 total = 0.0; 62 txtPrice.Text = ""; 63 txtNum.Text = ""; 64 lblTotalShow.Text = ""; 65 lbxList.Items.Clear(); 66 cbxType.SelectedIndex = 0; 67 } 68 69 private void txtNum_KeyPress(object sender, KeyPressEventArgs e) 70 { 71 //數字0~9所對應的keychar爲48~57 72 e.Handled = true; 73 //輸入0-9 74 if ((e.KeyChar >= 47 && e.KeyChar <= 58) || e.KeyChar == 8) 75 { 76 e.Handled = false; 77 } 78 } 79 80 private void txtPrice_KeyPress(object sender, KeyPressEventArgs e) 81 { 82 //數字0~9所對應的keychar爲48~57 83 e.Handled = true; 84 //輸入0-9 85 if ((e.KeyChar >= 47 && e.KeyChar <= 58) || (e.KeyChar == 8 || e.KeyChar==46)) 86 { 87 e.Handled = false; 88 } 89 } 90 91 private void frmMain_Load(object sender, EventArgs e) 92 { 93 //讀取配置文件 94 ds = new DataSet(); 95 ds.ReadXml(Application.StartupPath + "\\CashAcceptType.xml"); 96 //將讀取到的記錄綁定到下拉列表框中 97 foreach(DataRowView dr in ds.Tables[0].DefaultView) 98 { 99 cbxType.Items.Add(dr["name"].ToString()); 100 } 101 102 //要下拉選擇框在加載的時候,就選擇索引爲0的元素"正常消費" 103 cbxType.SelectedIndex = 0; 104 } 105 } 106 }
經過程序去讀XML的配置文件,來生成這個下拉列表框,而後再根據用戶的選擇,經過反射實時的實例化出相應的算法對象,最終利用策略模式計算最終的結果。
XML文件——CashAcceptType.xml代碼以下
1 <?xml version="1.0" encoding="utf-8" ?> 2 <CashAcceptType> 3 <type> 4 <name>正常消費</name> 5 <class>CashNormal</class> 6 <para></para> 7 </type> 8 <type> 9 <name>滿300返100</name> 10 <class>CashReturn</class> 11 <para>300,100</para> 12 </type> 13 <type> 14 <name>滿200返50</name> 15 <class>CashReturn</class> 16 <para>200,50</para> 17 </type> 18 <type> 19 <name>打8折</name> 20 <class>CashRebate</class> 21 <para>0.8</para> 22 </type> 23 <type> 24 <name>打7折</name> 25 <class>CashRebate</class> 26 <para>0.7</para> 27 </type> 28 <type> 29 <name>打5折</name> 30 <class>CashRebate</class> 31 <para>0.5</para> 32 </type> 33 </CashAcceptType>
如今不管需求是什麼,用如今的程序,只須要改改XML文件就所有擺平了。好比如今老闆以爲如今滿300送100太多了,要改爲送80,我只須要去XML文件裏改就好了。
注:如要添加新的算法,那麼該算法類繼承CashSuper,再去改一下XML文件就能夠了。