1. 程式人生 > >【設計模式】(一)-簡單工廠模式和策略模式

【設計模式】(一)-簡單工廠模式和策略模式

前言

最近開始和春哥,張鐸 ,銀平討論設計模式,成立了一個小菜變大鳥的小組,每天討論一個模式,並且把這個模式搞懂,每學一個新的模式,再回顧一下之前學的模式。這兩天學了簡單工廠模式和策略模式,發現兩個模式有很多相同之處,下面用商場促銷的例子來對兩個模式總結一下。

簡單工廠模式

1.首先建立一個抽象類,用以子類繼承,定義了抽象方法 acceptCash() 方法傳入引數 money

abstract class CashSuper
    {
        public abstract double acceptCash(double money);
    }

2.這裡定義了三個子類,分別處理 正常收費 , 打折 , 滿300返100 三種收費方法。

 class CashNormal : CashSuper
    {
        public override double acceptCash(double money)
        {
            return money;
        }

    }

        class CashRebate : CashSuper
    {
        private double rebate = 1d;
        public CashRebate(string Rebate)
        {
            rebate = Convert.ToDouble(Rebate);
        }
        public override double acceptCash(double Money)
        {
            return Money * rebate;
        }
    }



    class CashReturn : CashSuper
    {
        private double moneyCondition = 0.0d;
        private double moneyReturn = 0.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;
        }

    }

大話模式的第一章的簡單工廠模式是用父類實現多型,這裡體現的是用抽象類實現多型。
3.下面是工廠類

 public class CashFactory
    {
        public static CashSuper createCashAccept(string type)
        {
            CashSuper cs = null;
            switch (type)
            {
                case "正常收費":
                    cs = new CashNormal();
                    break;
                case "打八折":
                    cs = new CashRebate("0.8");
                    break;
                case "打七折":
                    cs = new CashRebate("0.7");
                    break;
                case "滿300返100":
                    cs = new CashReturn("300","100");
                    break ;
            }
            return cs;
        }

4.然後是客戶端的程式碼

       public Form1()
        {
            InitializeComponent();
        }
        double total = 0.0d;
        private void button1_Click(object sender, EventArgs e)
        {
            CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
            double totalPrices = 0d;
            totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
            total = total + totalPrices;
            lbxList.Items.Add("單價:" + txtPrice.Text +"數量:" + txtNum.Text + cbxType.SelectedItem + "合計:" + totalPrices.ToString());
            label4.Text = total.ToString();
            
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cbxType.Items.AddRange(new object[] { "正常收費", "打八折", "滿300返100"});
            cbxType.SelectedIndex = 0;
        }
    }

首先建立 CashSuper 物件,呼叫工廠類的 createCashAccept()方法,根據傳入的字串(正常收費,打八折)返回相應的 CashSuper 物件,然後執行剛才複寫的 acceptCash()方法,傳入引數 money 進行計算。

優點:通過使用工廠類,外界可以從直接建立具體產品物件的尷尬局面擺脫出來,僅僅需要負責“消費”物件就可以了。而不必管這些物件究竟如何建立及如何組織的.明確了各自的職責和權利,有利於整個軟體體系結構的優化。

缺點:由於工廠類集中了所有例項的建立邏輯,違反了高內聚責任分配原則,將全部建立邏輯集中到了一個工廠類中;它所能建立的類只能是事先考慮到的,如果需要新增新的類,則就需要改變工廠類了。

策略模式

策略模式的概念:策略模式定義了演算法家族,分別封裝起來,讓他們之間可以相互替換,策略模式讓演算法的變化不會影響到使用演算法的客戶。

同樣的例子使用策略模式更改一下,CashSuper和三種處理方法不用更改,只需在簡單工廠基礎上新增 CashContext 類:

 class CashContext
    {
        private CashSuper cs;
 
        public CashContext(CashSuper csuper)
        {
            this.cs = csuper;
        }
 
        public double GetResult(double money)
        {
            return cs.acceptCash(money);
        }

客戶端程式碼如下,將相應的策略物件作為引數傳入 CashContext 物件中:

 private void button1_Click(object sender, EventArgs e)
        {
            CashContext cc = null ;
            switch(cbxType .SelectedItem.ToString())
            {
                case "正常收費":
                    cc = new CashContext (new CashNormal());
                    break ;
                case "打八折":
                    cc = new CashContext (new CashRebate("0.8"));
                    break ;
                case "滿300返100":
                    cc = new CashContext (new CashReturn("300","100"));
                    break ;
            }
            double totalPrice = 0d;
            totalPrice = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));

比較簡單工廠的方法知道,簡單工廠需要客戶端認識兩個類 CashSuper 和 CashFactory ,而策略模式客戶端只需要認識 CashContext 類就可以了,使得具體的收費演算法徹底與客戶端分離,耦合度更加降低。

策略與簡單工廠結合

改造後的CashContext:將例項化具體策略的過程由客戶端轉移到Context類種。

class CashContext
    {
        CashSuper cs = null;

        public CashContext(string type)
        {
            switch (type)
            {
                case "正常收費":
                    CashNormal cs0 = new CashNormal();
                    cs = cs0;
                    break;
                case "滿300返100":
                    CashReturn cr1 = new CashReturn("300","100");
                    cs = cr1;
                    break;
                case "打八折":
                    CashRebate cr2 = new CashRebate("0.8");
                    cs = cr2;
                    break;
          
                    }
        }
        public double GetResult(double money)
        {
            return cs.acceptCash(money);
        }
    }
}

客戶端端程式碼如下:

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        double total = 0.0d;
        private void button1_Click(object sender, EventArgs e)
        {
            CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
            double totalPrices = 0d;
            totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
            total = total + totalPrices;
            lbxList.Items.Add("單價:" + txtPrice.Text +"數量:" + txtNum.Text + cbxType.SelectedItem + "合計:" + totalPrices.ToString());
            label4.Text = total.ToString();
            
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cbxType.Items.AddRange(new object[] { "正常收費", "打八折", "滿300返100"});
            cbxType.SelectedIndex = 0;
        }
    }

總結

比較簡單工廠的方法知道,簡單工廠需要客戶端認識兩個類 CashSuper 和 CashFactory ,而策略模式客戶端只需要認識 CashContext 類就可以了,使得具體的收費演算法徹底與客戶端分離,耦合度更加降低。

剛開始學,感覺學的還不夠深入,如有錯誤,還望指教。