C#設計模式系列菜單-『Strategy Pattern』

摘要: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的介面,有需要那個動作的人在去拿它…好嗎… (好可憐的創造者)
 
 
定義問題:為啥不用Interface
1.因為透過Interface時每個類別都要實作,當有100個子類別繼承該介面時,你就會寫到死了。
2.如果100個子類中又有50個實作是相同的內容,這就代表你重覆寫了不少Code。
3.如果又加其它行為進來,那又要在改很多了。
 

 

這時我們決定要使用幾個設計守則
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("對不起我還很菜不會飛" );
        }

    }

 

開始產生變型金剛~
 private void button1_Click(object sender, EventArgs e)
        {
            //實體化博派第一台測試機。
            AutobotTransformer Test1 = new AutobotTransformer();
            Test1.Heart();
            Test1.performFly();
          

            //實體化狂派第二台測試機。
            DecepticonTransformer Test2 = new DecepticonTransformer();
            Test2.Heart();
            Test2.performFly();
           
           
        }

 

執行結果
 

 



小弟才書學淺~請各位客官指教指教~~~

小弟日 : 你要知道自已不是帥哥,你才有可能變成帥哥 。