摘要:C#設計模式系列菜單-『Strategy Pattern』
~哀悼~ 給予不幸的人。
前言
本系列文章基本上為Head First Design Patterns 的筆記,在程式設計中,有時你會偶到一種很恐怖的現象,一個小小的需求,你需要花很多時間修改,一個小小的變動,幾乎把所有程式碼修改過一次,最後就變成只要追求程式可以跑就好…因為沒心力再調整了。將之前在某家公司寫Code的花費時間計算一下,我幾乎所有的時間都花在因為設計不良的軟體上。惡夢啊~~ 。
Design Pattern是什麼呢~ 嚴格來說是可以盡量幫你把上述的情況減到最少的方法,以軍事武器形容來說,Design Pattern屬於『戰略兵器』,戰略兵器是什麼呢?核彈就是戰略兵器,用最簡單的說法來解釋就是,你打一發,就可以改變整個戰局。Design Pattern 使用的好,幾乎可以改變一家軟體公司的工作時間與產出效率。
我們在這篇文章將要介紹第一個Design Pattern 『Strategy Pattern』他的定義如下
定義 :
『策略模式』定義了演算法家族,個別封裝起來讓它們之間可以互相替換,此模式讓演算法的變動,不會影響到使用演算法的程式。
本章設計守則
1.找出程式中可能需要更動之處,把它們獨立出來,不要和那些不需要更動的程式碼混在一起。
2.寫程式是針對介面寫,而不是針對實踐方式而寫。
3.多用合成,少用繼承。
範例與說明
假如我現在是賽伯坦星的創造者,我現在要建立一個『變型金剛』的類別。
//建立變型金鋼類別
class Transformer
{
//建立速度欄位。
private int speed;
//建立能量欄位。
private int power;
//建立速度屬性
public int Speed
{
get { return speed; }
set { speed = value ; }
}
//建立能量屬性
public int Power
{
get { return power; }
set { power = value ; }
}
public void Run()
{
Console.WriteLine("我很會跑喔" );
}
}
然後我們要開始建造『博派』和『狂派』
//博派
class DecepticonTransformer: Transformer
{
public void Heart()
{
Console.WriteLine("我是狂派,我是壞人~ 呼呼~" );
}
}
//狂派
class AutobotTransformer: Transformer
{
public void Heart()
{
Console.WriteLine("我是博派我是好人" );
}
}
這時有人說:變型金剛不是都會飛嗎?著麼沒有飛的方法呢???
第1代創造者說:喔好吧…那我在父類別增加Fly()的方法。
定義問題: 為啥不用繼承
1.有些類別不需要飛的方法,例如第一集的變型金剛…
2.我們也可以用override 來解決第一種問題,但如果有100個子類別不需要飛行時就代表你要寫100次的
override的方法。
密卡登: 有沒有腦 ?? 那些下三爛的博派都還在地上爬,要會飛還要等第二集啊 !!!
第1代創造者: 好吧那就只在狂派類別增加飛的方法。
柯伯文: 可是我在第二集就會飛了啊!!! ,難到要到第二集你還要在改一次程式 ????
第1代創造者: 呃~ 好吧那我創造一個IFly的介面,有需要那個動作的人在去拿它…好嗎… (好可憐的創造者)
這時我們決定要使用幾個設計守則
1.找出程式中可能需要更動之處,把它們獨立出來,不要和那些不需要更動的程式碼混在一起。
2.寫程式是針對介面寫,而不是針對實踐方式而寫。
3.多用合成,少用繼承。
之前的作法是『行為繼承自父類別』或『繼承至某介面並由子類別自行實作而來』。但這兩種作法都是依賴『實作』,我們被實作綁的死死的,沒辦法更改行為(除非寫更多程式碼)。
因此我們決定將Fly這個行為獨立出來,專門來設計變型金剛飛的行為,我們利用介面代表每個行為,並運用類別來實作每一種介面的方法。
所以這次變型金剛類別不會實作IFly,反而由『其它類別專門實作這些行為』。這就種類別被稱為『行為類別』。
這樣的設計,可以讓飛行的動作被其他的物件再三利用,因為這些行為已經與變型金剛類別無關了。而我們可以新增一些行為,不會影響到既有的行為,也不會影響有『使用』到飛行行為的變型金剛類別。
注:
多用合成,少用繼承,其中合成是什麼呢?當你將兩個類別結合起來使用,如同本例,這就就是合成物。這種作法和『繼承』不同在於,變型金剛的行為不是繼承而來,而是和適當的行為物件『合成』而來。
第100代創造者:我決定把Fly行為整個拉出來,建立一個IFly介面代表行為,並且在其它類別(FlyWithLight與FlyWithRocket) 上實作這Fly的方法。
程式碼修改為
Transformer 類別
//建立變型金鋼類別
abstract class Transformer
{
//宣告為介面型態的變數。
//每個變數會利用多型的方式在執行期取用到正確的動作。
public IFly FlyBehavior;
//建立速度欄位。
private int speed;
//建立能量欄位。
private int power;
//建立速度屬性
public int Speed
{
get { return speed; }
set { speed = value ; }
}
//建立能量屬性
public int Power
{
get { return power; }
set { power = value ; }
}
public void Run()
{
Console.WriteLine("我很會跑喔" );
}
//不親自處理飛行行為,而是委由FlyBehavior物件幫忙處理。
public void performFly()
{
FlyBehavior.Fly();
}
}
博派 AutobotTransformer類別 ,繼承Transformer
//博派
class AutobotTransformer : Transformer
{
public AutobotTransformer()
{
FlyBehavior = new FlyNoWay ();
}
public void Heart()
{
Console.WriteLine("我是博派我是好人" );
}
}
狂派 DecepticonTransformer,繼承Transformer
//狂派
class DecepticonTransformer : Transformer
{
public DecepticonTransformer()
{
FlyBehavior = new FlyWithRocket ();
}
public void Heart()
{
Console.WriteLine("我是狂派,我是壞人~ 呼呼~" );
}
}
飛行行為IFly 介面
interface IFly
{
void Fly();
}
行為類別1 - FlyWithRocket 用火箭飛行的飛行行為
class FlyWithRocket :IFly
{
public void Fly()
{
Console.WriteLine("我用火箭推進飛行" );
}
}
行為類別2-FlyNoWay 不會飛行的飛行行為
class FlyNoWay: IFly
{
public void Fly()
{
Console.WriteLine("對不起我還很菜不會飛" );
}
}
開始產生變型金剛~