讀《大話設計模式》——應用策略模式的"商場收銀系統"(WinForm)

策略模式的結構算法

這個模式涉及到三個角色:數組

環境(Context)角色:持有一個 Strategy 類的引用。
抽象策略(Strategy)角色:這是一個抽象角色,一般由一個接口或抽象類實現。此角色給出全部的具體策略類所需的接口。
具體策略(ConcreteStrategy)角色:包裝了相關的算法或行爲。ide

 

 

上篇博文寫的CashSuper 就是抽象策略,而正常收費 CashNormal、打折收費 CashRebate 和返利收費 CashReturn 就是三個具體策略,也就是策略模式中說的具體算法。this

   附上上篇博文的部分代碼spa

//正常消費,繼承CashSuper
    class CashNormal:CashSuper
    {
        public override double acceptCash(double money)
        {
            return money;
        }
    }
View Code
//打折收費消費,繼承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;
        }
    }
View Code
//返利收費
    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;
        }
    }
View Code
//現金收取父類
    abstract class CashSuper
    {
        //抽象方法:收取現金,參數爲原價,返回爲當前價
        public abstract double acceptCash(double money);
    }
View Code

  加入的策略模式(這裏能夠棄用工廠模式了).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文件就能夠了。

相關文章
相關標籤/搜索