(200-07-14) C#.NET 策略模式與簡單工廠模式

摘要:策略模式與簡單工廠模式

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

PS:演算法本身只是一種策略,最重要的是這些演算法是隨時都可能互相替換的,這就是變化點,而封裝變化點是物件導向的一種很重要的思維方式。

 

案例類別圖

情境:百貨公司做活動判定需給贈品 ,判定方式為 1.純發票 2.需要卡號 (演算法的變異點)StrategyPattern.rar

例:

父類別

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
    abstract class RuleDecide
    {
        //建立可給子類別所使用的 DataFiled 與 Method
        private String _ruleCaption; //活動名稱
        private DateTime _ruleDate;//活動日期
        
        public RuleDecide(String _ruleCaption,DateTime _ruleDate) //參數建構子
        {
            this._ruleCaption = _ruleCaption;
            this._ruleDate = _ruleDate;
        }

        //可給子類別使用的Method
        public void displayRuleBaseInfo()
        {
            System.Console.WriteLine(String.Format("活動名稱:{0} 活動時間:{1}",this._ruleCaption,this._ruleDate.ToString("yyyy-MM-dd")));
        }

        //重點:建構可覆寫的方法(Method)
        public abstract void DecideMethod(); //建立抽象方法 Abstract Method
    }
}

子類別(發票)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
    class RuleByInvoice:RuleDecide
    {
        public RuleByInvoice(String _ruleCaption, DateTime _ruleDate):base(_ruleCaption,_ruleDate) //繼承父類別的建構子
        {
        }
        public override void DecideMethod()
        {
            System.Console.WriteLine("活動是用發票來判定的!!");
        }
    }
}

子類別(卡號)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
    class RuleByCard:RuleDecide
    {
        public RuleByCard(String _ruleCaption,DateTime _ruleDate):base(_ruleCaption,_ruleDate)
        {
        }

        public override void DecideMethod()
        {
            System.Console.WriteLine("活動是用卡別來判定的!!");
        }
    }
}

Context類別

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
    class RuleContext
    {
        private RuleDecide _rd;

        public RuleContext(RuleDecide _rd) //透過建構子傳入繼承 RuleDecide 類別的物件
        {
            this._rd = _rd;
        }

        // 建議使用:一般傳入字串的建構式
        public RuleContext(String _decideMtthodName, String _ruleCaptoin, DateTime _ruleDate)
        {
            switch (_decideMtthodName)
            {
                case "發票活動":
                    _rd = new RuleByInvoice(_ruleCaptoin, _ruleDate);
                    break;
                case "卡號活動":
                    _rd = new RuleByCard(_ruleCaptoin, _ruleDate);
                    break;
            }
        }
        // 建議使用:傳入列舉的建構式
        public RuleContext(Decide _decideMtthodName, String _ruleCaptoin, DateTime _ruleDate)
        {
            switch (_decideMtthodName)
            {
                case Decide.發票判斷:
                    _rd = new RuleByInvoice(_ruleCaptoin, _ruleDate);
                    break;
                case Decide.卡號判斷:
                    _rd = new RuleByCard(_ruleCaptoin, _ruleDate);
                    break;
            }
        }



        public void RuleDecideMethod()
        {
            _rd.displayRuleBaseInfo();
            _rd.DecideMethod();
        }
    }
}

列舉

enum Decide
{
    發票判斷,卡號判斷
}

 

主程式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
    class Program
    {
        /// <summary>
        /// 策略模式展式
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //RuleDecide rd=new RuleByInvoice("活動1:需用發票判定",new DateTime(2010,12,05));
            //rd.displayRuleBaseInfo();
            //rd.DecideMethod();
            //RuleDecide rd1 = new RuleByCard("活動2:需用卡號判定", new DateTime(2009, 10, 05));
            //rd1.displayRuleBaseInfo();
            //rd1.DecideMethod();

            //透過 RuleContext類別 介面層 不需要知道如何去實作哪些內容)。
            RuleContext rc=new RuleContext(new RuleByInvoice("活動3:發票判定",new DateTime(2007,05,10)));
            rc.RuleDecideMethod();
            System.Console.WriteLine("--------------------------------------------------------------------");

            //透過簡單工廠模式介面層不需去考慮要建構哪個物件。
            RuleContext rc1=new RuleContext("卡號活動","活動4:卡號判定",new DateTime(2007,05,10));
            rc1.RuleDecideMethod();
            System.Console.WriteLine("--------------------------------------------------------------------");
            //1.透過簡單工廠模式與列舉(主要規範入傳入參數的變動性)。
            //2.介面層不需去考慮要建構哪個物件。
            RuleContext rc2 = new RuleContext(Decide.發票判斷, "活動5:發票判定", new DateTime(2008, 04, 10));
            rc2.RuleDecideMethod();

        }
    }
}

執行結果: