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


