策略模式 => 我希望用戶只認識我 連實際他的需求是哪個子類別在做都不要知道
考量前一篇 簡單工廠時 用戶端叫用的程式碼為
static void Main(string[] args)
{
Housework housework = HomeworkFactory.CreateHousework("掃地");
housework.Do();
}
等於用戶端得同時認識
1. 當下實際得到哪個 Housework 的子類別 ex: 可能是掃地、洗碗、倒垃圾
2. 還得知道 HomeworkFactory (畢竟要用哪個子類別是他幫我們分派的)
3. 父類別.Do()
而假設我們今天的需求為 只要有 Do() 就好
實際是哪個子類別在Do() 主程式不用知道 => 我想把子類別在主程式中隱藏起來
因為在主程式中的程式碼越單純 未來程式碼有變動時 要改的地方就越少 越集中
一樣先來看看最重要的 Context 的程式碼
/// <summary>
/// 實際用到哪個子類別完全在 Context 中完成
/// 命名 => xxxContext
/// </summary>
class DiscountContext
{
//重點!!! 父類別相依於 Context 而不是主程式 不會再曝露任何資訊給外人
private Discount _disc;
//工廠模式傳回一個類別 策略模式不用傳回任何東西
//因為實際用哪個類別外人不會知道 不用跟外人說
//都是在內部 (建構子) 完成的
public DiscountContext(string type)
{
switch (type)
{
case "買一送一":
_disc = new Buy1Get1Free();
break;
case "半價":
_disc = new HalfPrice();
break;
case "無折扣":
_disc = new NoDiscount();
break;
}
}
//父類別的方法又被我包一層 因為對外我希望大家都透過 Context 存取所有東西 不需再跟其他人有關聯
public int GetPrice(int orgPrice)
{
return _disc.Calculate(orgPrice);
}
}
可得知為了達成一切都透過 Context 完成就好 不要再跟其他人有瓜葛 我們得做兩件事
1. Context 內有一個私有的父類別變數 實際是對應到哪個子類別 在建構子中決定
2. 父類別的 func 在 Context 中再包一層 所以主程式 call 的是 Context 的 Func 而非主程式的 Func
最後達成 => 斷開主程式與類別之間的藕合
所以主程式會長得像
/// <summary>
/// 主程式完全不知道實際是用哪個子類別
/// </summary>
static void Main(string[] args)
{
string strategy = "買一送一";
DiscountContext context = new DiscountContext(strategy);
//簡單工廠模式叫用的 func 在父類別中
//策略模式叫用的 func 就在 Context 中
//所以策略模式的主程式只需要用到 Context 不用知道父類別是誰
//未來如果程式有變動 主程式要改的地方就更少了
var price = context.GetPrice(100);
}
那最後我們就能看看完整的程式碼長怎樣了
namespace ConsoleApplication1
{
class Program
{
/// <summary>
/// 主程式完全不知道實際是用哪個子類別
/// </summary>
static void Main(string[] args)
{
string strategy = "買一送一";
DiscountContext context = new DiscountContext(strategy);
//簡單工廠模式叫用的 func 在父類別中
//策略模式叫用的 func 就在 Context 中
//所以策略模式的主程式只需要用到 Context 不用知道父類別是誰
//未來如果程式有變動 主程式要改的地方就更少了
var price = context.GetPrice(100);
}
}
//-----------------------------------------------------------------------------------------------
/// <summary>
/// 實際用到哪個子類別完全在 Context 中完成 不會再曝露任何資訊給外人
/// 命名 => xxxContext
/// </summary>
class DiscountContext
{
//重點!!! 父類別相依於 Context 而不是主程式
private Discount _disc;
//工廠模式傳回一個類別 策略模式不用傳回任何東西
//因為實際用哪個類別外人不會知道 不用跟外人說
//都是在內部 (建構子) 完成的
public DiscountContext(string type)
{
switch (type)
{
case "買一送一":
_disc = new Buy1Get1Free();
break;
case "半價":
_disc = new HalfPrice();
break;
case "無折扣":
_disc = new NoDiscount();
break;
}
}
//父類別的方法又被我包一層 因為對外我希望大家都透過 Context 存取所有東西 不需再跟其他人有關聯
public int GetPrice(int orgPrice)
{
return _disc.Calculate(orgPrice);
}
}
//-----------------------------------------------------------------------------------------------
abstract class Discount
{
public abstract int Calculate(int orgPrice);
}
class Buy1Get1Free : Discount
{
public override int Calculate(int orgPrice)
{
//買一送一 以價高者計費
return -1;
}
}
class HalfPrice : Discount
{
public override int Calculate(int orgPrice)
{
//售價 / 2
return -1;
}
}
class NoDiscount : Discount
{
public override int Calculate(int orgPrice)
{
//原價
return -1;
}
}
}