1. 程式人生 > >簡單工廠與策略模式

簡單工廠與策略模式

     時間過得好快,不知不覺又到了寫部落格的time了;這次簡單介紹一些簡單工廠、策略模式,還有他們的區別和聯絡,恩,進入正題:

抽象理論藉助具體例項更有助於理解,這次藉助我們熟知的“商場促銷”,效果圖:      

兩個模式相同的程式碼部分: 

 //客戶端
        double total=0.0d;
        private void Form1_Load(object sender, EventArgs e)
        {
            cmdCount.Items.AddRange(new object[] { "正常收費", "打八折", "打七折", "打五折" });

            cmdCount.SelectedIndex = 0;
        }
        //現金收費抽象類
        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)
            {
                //打折收費,初始化時輸入折扣率:如0.8
                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;
            //返利收費,初始化輸入返利條件,返利值
            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;
            }
        }

   CashSuper、CashNormal、CashRebate、CahReturn是具體的子類,他們裡面的acceptCash方法是對CashSuper.acceptCash這一虛方法的重寫,使其變成帶有各自Signet的方法 。               

建立型模式 ,它關注物件建立,提供建立物件的介面. 
  一個工廠類,負責根據不同的打折優惠方法來使用不同的子類,呼叫相應的方法計算結果、顯示資訊。
   class CashFactory
        {
            //現金收取工廠
            //不同的情況,可增加分支
            public static CashSuper createCashAccept(string type)
            {
                CashSuper cs = null;
                switch (type)
                {
                    case"正常收費":
                        cs = new CashNormal();
                        break;
                    case "滿300返100":
                        CashReturn cr1=new CashReturn ("300","100");
                        cs=cr1 ;
                        break ;
                    case"打八折":
                        CashRebate cr2 = new CashRebate("0.8");
                        cs = cr2;
                        break;
                }
                return cs;
            }
        }
        private void btnSure_Click(object sender, EventArgs e)
        {
            //簡單工廠模式,根據下拉列表框生成相應的物件
            CashSuper csuper = CashFactory.createCashAccept(cmdCount.SelectedItem.ToString());
            double totalPrices = 0d;
            //csuper自帶物件,用相應的acceptCash方法計算
            totalPrices = csuper.acceptCash(Convert.ToDouble(txtprice.Text)
                * Convert.ToDouble(txtNum.Text));

            total = total + totalPrices;
            //顯示在listbox中
            lstSum.Items.Add("單價:" + txtprice.Text + "數量" + txtNum.Text + ""
                + cmdCount.SelectedItem + "合計" + totalPrices.ToString());
           //顯示總計
            lblSum.Text = total.ToString();
        }

     違反了“開閉原則”:由於工廠類集中了所有例項的建立邏輯,違反了高內聚責任分配原則(GRASP職責分配原則),將全部建立邏輯集中到了一個工廠類中;它所能建立的類只能是事先考慮到的,如果需要新增新的類,則就需要改變工廠類,很難避免模組功能的蔓延,對系統的維護和擴充套件非常不利。

策略模式

     物件行為型模式 ,它關注行為和演算法的封裝 ,通常把一個系列的演算法封裝到一系列的策略類裡面    它定義一系列的演算法,並對演算法進行封裝,演算法間可以相互替換。把演算法的責任和演算法本身分割開委派給不同的物件管理。演算法可獨立於使用它的客戶而變化。 改模式中應當由客戶端自己決定在什麼情況下使用什麼具體策略角色。
<span style="font-family:KaiTi_GB2312;font-size:18px;">  private void btnSure_Click(object sender, EventArgs e)</span><span style="font-family: Arial; font-size: 14px;">
        {
            CashContext cc = null;
            //下拉列表,相應策略、傳人
            switch (cmdCount .SelectedItem.ToString ())
            {
                case"正常收費":
                    //相應的方法
                    cc = new CashContext(new CashNormal());
                    break;
                case "滿300返100":
                    cc = new CashContext(new CashReturn("300", "100"));
                    break;
                case "打8折":
                    cc = new CashContext(new CashRebate("0.8"));
                    break;
            }
            double totalPrices = 0d;
            totalPrices = cc.GetResult(Convert.ToDouble(txtNum.Text) * Convert.ToDouble(txtprice.Text));

            total = total + totalPrices;
            lstSum.Items.Add("單價" + txtprice.Text + "數量" + txtNum.Text
                + " " + cmdCount.SelectedItem + "合計:" + total.ToString());
            lblSum.Text = total.ToString();
        }
        class CashContext
        {
            //宣告一個cashsuper物件
            private CashSuper cs;
            //傳入具體收費策略
            public CashContext (CashSuper csuper)
            {
                this.cs = csuper;
            }
            //根據策略、運用方法、計算結果
            public double GetResult(double money)
            {
                return cs.acceptCash(money);
            }
        }
</span>
  策略模式並不決定在何時使用何種演算法,演算法的選擇由客戶端來決定。這在一定程度上提高了系統的靈活性,但是客戶端需要理解所有具體策略類之間的區別,以便選擇合適的演算法,這也是策略模式的缺點之一,在一定程度上增加了客戶端的使用難度。並且 Strategy和Context之間的通訊開銷、策略模式將造成產生很多策略類等等不足之處使得策略模式在某些方面存在缺陷。     簡單工廠模式和策略模式各有優缺,取長補短是人類的智慧。

簡單工廠和策略模式的結合

      private void btnSure_Click(object sender, EventArgs e)
        {
            //將相應的演算法字串傳人cashcontext物件中
            CashContext csuper = new CashContext(cmdCount.SelectedItem.ToString());
            double totalPrices = 0d;
            //計算總價
            totalPrices = csuper.GetResult(Convert.ToDouble(txtNum.Text) * Convert.ToDouble(txtprice.Text));
            total = total + totalPrices;
            //顯示
            lstSum.Items.Add("單價" + txtprice.Text + "數量" + txtNum.Text
                + " " + cmdCount.SelectedItem + "合計:" + total.ToString());
            lblSum.Text = total.ToString();
        }

        class CashContext
        {
            //宣告一個cashsuper物件
             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);
            }
        }
很不錯的一個連結:介紹策略模式的 http://blog.csdn.net/hguisu/article/details/7558249  最後的例子亮了閉嘴
    吃飯,策略模式的做法:有幾種方案供你選擇,選擇去餐廳好呢還是自己做,完全由人自行決定去構建吃飯方案(你自己需要去買餐廳,或者做飯)。而工廠模式是你決定哪種吃飯方案後,不用關注這吃飯方案怎麼給你建立,也就是說你告訴我方案的名稱就可以了,然後由工廠代替你去構建具體方案(工廠代替你去做飯)。
thanks for your time微笑