摘要:策略模式與簡單工廠模式
策略模式(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(); } } }
執行結果: