[Design Pattern] 策略(Strategy)模式 - 把變化給封裝起來
策略模式:
定義完成相同工作的一系列演算法,這些個別的演算法都是針對某個特定相同的工作
,差別在於各別演算法本身的商業邏輯不同,將這些演算法個別封裝起來便於抽換,
維護上彼此間是獨立的,不會因某個演算法的修改,而影響到其它的演算法,而慨念
上外界調用的方式是相同的。
情境示範:
棒球打擊,有不同的打擊策略,強力揮擊、選球巧打、短打、突襲短打,但若以抽象
角度來看,不管哪一種打擊策略都叫做打擊,差別在於打擊用的力道等細部內容的不同
參在一起做瀨尿牛丸寫法:
/// <summary>
/// <summary>
/// 打擊
/// </summary>
/// <param name="swimtype">打擊型態</param>
public void Swim(string swimtype)
{
switch (swimtype)
{
case "Power":
//強力揮擊
break;
case "Bunt":
//短打
break;
case "Squeeze Bunt":
//突襲短打
break;
case "Clever":
//選球巧打
break;
}
}
這樣的寫法把不同的打擊策略內容細部的Logic全寫在一起,用條件式的寫法分開,缺點在於
日後策略若有增減則要拿出來調整,一不小心容易動到不應動的程式Logic,此外變動的是打
擊策略內容,而非打擊的這個動作,這樣的設計方式違反開放-封閉原則,且程式碼也會變
的又臭又長。
運用Strategy Pattern的寫法:
(1)首先為打擊這件事建立一個抽象類別(可以是interface or abstract ),定義一個執行揮棒的方法
/// <summary>
/// 抽象策略的角色:
/// 做為實體化策略的接口
/// </summary>
public interface ISwimStrategy
{
void Exec();
}
(2)針對不同的打擊策略,建立各自的class,並繼承ISwimStrategy介面且實作其Exec方法
public class CleverSwim:ISwimStrategy
{
/// <summary>
/// 實作選球巧打打擊策略Logic
/// </summary>
public void Exec()
{
System.Web.HttpContext.Current.Response.Write("選球巧打");
}
}
(3)接著打擊是棒球中的一個動作過程,因此我們建立一個名為BaseBall的Class,並且有著打擊
這個方法,而該方法的執行則是利用ISwimStrategy建立具可抽換的機制
(4)外界的呼叫
DesignPattern.Strategy.BaseBall baseball = new DesignPattern.Strategy.BaseBall();
baseball.Swim(new DesignPattern.Strategy.PowerSwim());
因此整個架構看起來會清爽的多,而且每個打擊策略內部Logic調整變動,均不會對其它的Class產生
影響,只要確保對外都是利用ISwimStrategy介面來做為接口就可以,彼此間偶合程度可以降低,以
後只要有新的打擊策略要增加,只需要再建立另一個新的打擊策略Class,並繼承ISwimStrategy介面
,實作Exec()即可
結論:
從這裡我們可以看的出來,Stategy模式在於把變化的部份給封裝起來,外界不需要去了解如何變化,
只需要知道想選用哪一種,並用共同的方式進行呼叫執行,此外這樣的模式也便於我們抽換不同的實作
Logic,不需要為了擴充而把不相干或不會動到的類別給打開來進行修改,一來也避免了因擴充了B,而
使用原本的A可能壞掉的風險
以上若有描述不當的地方,歡迎指正囉
By No.18