1. 程式人生 > >對設計模式的總結之簡單工廠與策略模式

對設計模式的總結之簡單工廠與策略模式

mage 建立 不變 href catch nag 實現類 初步 cti

前言

面向對象編程追求的本質-提高擴展性、可維護性、靈活性和復用性。合理利用面向對象6個原則,能夠很好的達到要求。如何利用好就是至關重要的了,前人總結了23+個設計模式能夠讓初學者更容易學到其中的精髓,本文就說說我對本人對簡單工廠模式、策略模式的見解。

簡單工廠模式與策略模式

簡單工廠模式

工作中,常常遇到需要做一個功能(鴨子),這個功能中含有可控個數的子操作功能(鴨子叫,鴨子跑,鴨子飛),而且子功能在不同的情況下處理方式又不相同(成年鴨子/小鴨子叫,成年鴨子/小鴨子跑,成年鴨子/小鴨子飛)。我們首先就會想到,用簡單工廠模式哇。創建一個該功能的抽象基類,再創建多個實現不同邏輯的子類繼承它。最後建立一個工廠類,通過工廠類中類型判斷可生成不同的該功能子類實例。客戶端最後調用工廠和抽象基類操作即可。實現類與類松耦合,既簡單又實用。

技術分享

基本用法

  1. 技術分享
        /// <summary>
        /// 工廠類
        /// </summary>
        public class GameOfInteractive
        {
            /// <summary>
            /// 遊戲返回基類
            /// </summary>
            private static GameAbstract gameServiceCall = null;
    
            /// <summary>
            /// 工廠構造類
            
    /// </summary> /// <param name="gameType"></param> public static GameAbstract GameService(int gameType) { try { switch (gameType) { case 1: gameServiceCall = new
    Sparrow(); break; case 2: gameServiceCall = new ShootBirds(); break; default: break; } } catch (Exception ex) { throw ex; } return gameServiceCall; } } /// <summary> /// 抽象基類 /// </summary> public abstract class GameAbstract { /// <summary> /// 遊戲登錄 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public abstract string Login(string sLoginName, string sPsw); /// <summary> /// 遊戲退出 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public abstract string LoginOut(string sLoginName, string sPsw); } /// <summary> /// XX遊戲具體類 /// </summary> public class ShootBirds: GameAbstract { /// <summary> /// 遊戲登錄 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public override string Login(string sLoginName, string sPsw) { return "我通過HTTP請求和XX遊戲服務交互進行登錄"; } /// <summary> /// 遊戲退出 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public override string LoginOut(string sLoginName, string sPsw) { return "我通過HTTP請求和XX遊戲服務交互,傳輸sLoginName和sPsw,通知客戶下線"; } } /// <summary> /// YY遊戲操作類 /// </summary> public class Sparrow : GameAbstract { /// <summary> /// 遊戲登錄 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public override string Login(string sLoginName, string sPsw) { return "我通過socket和YY遊戲服務交互進行登錄"; } /// <summary> /// 遊戲退出 /// </summary> /// <param name="sLoginName"></param> /// <param name="sPsw"></param> /// <returns></returns> public override string LoginOut(string sLoginName, string sPsw) { return "我通過socket和YY遊戲服務交互,傳輸sLoginName和sPsw,通知客戶下線"; } }
    View Code

總結

優缺點:工廠模式初步滿足了開放-封閉原則;工廠的使用,降低了對象之間的耦合性,做到了責任分離(客戶端不直接創建對象實例,生產實例交給工廠來做)。

工廠與消費者、原料間的聯系都很緊,如果工廠出了問題,與之相關的所有功能都將癱瘓;每次功能擴展,都需要改動工廠類,違反了高內聚責任分配原則。

使用場景:一般只在很簡單的情況下應用。eg:多數據庫選擇,登錄系統與其他系統做簡單信息交互操作等。

策略模式

萬物隨時變,唯一不變的就是變化。實體經濟蕭條,商場生意不如以往,不想被拍死在沙灘上,就必須增加新的刺激消費的活動 。eg:滿100返10,滿500送自行車,會員卡送積分(積分可以換商品),多級會員打折等促銷等方式。這些促銷方式不是一次性就定下來的,是隨著時間的改變產生的,如果在商場計價系統中直接用簡單工廠模式,算法經常更改,工廠也隨之更改,維護和擴展成本都會逐步增加。考慮到計價功能單一,每個子功能都只做計價,結構固定。可以把具體使用那種計價方式的任務交給客戶端來控制,這樣就產生了策略模式。策略模式與簡單工廠模式很像,都有功能基類和各種擴展的子功能類,唯一不同的就是策略模式強調的是算法封裝,不同的算法,用相應的子類進行實現

技術分享

基本用法

  1. 技術分享
    /// <summary>
        /// 環境角色
        /// </summary>
        public class Context
        {
            /// <summary>
            /// 需要的策略
            /// </summary>
            private AbstractStrategy strategy = null;
    
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime"></param>
            /// <returns></returns>
            public decimal CalculateSalary(int overtime)
            {
                return strategy.CalculateSalary(overtime);
            }
        }
        /// <summary>
        /// 抽象策略角色
        /// </summary>
        public abstract class AbstractStrategy
        {
    
            protected  static int baseOvertime = 80;//每個月基礎加班時間
    
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime">加班時間</param>
            /// <returns></returns>
            public abstract decimal CalculateSalary(int overtime);
        }
        /// <summary>
        /// 工人工資計算
        /// </summary>
        public class WagesForWorkmen:AbstractStrategy
        {
            private static decimal baseSalary = 2800;//基礎工資
    
            private static decimal overtimeSalary = 37.5M;//每小時加班費
    
            private static decimal extraSubsidies = 8.6M;//超出基礎加班時間後每小時另加補助費用
    
    
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime">加班時間</param>
            /// <returns></returns>
            public override  decimal CalculateSalary(int overtime)
            {
                decimal actuallySalary = baseSalary;
                if (overtime> baseOvertime)
                {
                    actuallySalary += overtimeSalary * baseOvertime + (overtime - baseOvertime) * (overtimeSalary + extraSubsidies);
                }
                else
                {
                    actuallySalary += overtimeSalary * overtime;
                }
                return actuallySalary;
            }
        }
        /// <summary>
        /// 組長工資計算
        /// </summary>
        public class WagesForGroupLeader:AbstractStrategy
        {
            private static decimal baseSalary = 2800;//基礎工資
    
            private static decimal postSalary = 800;//崗位工資
    
            private static decimal overtimeSalary = 40M;//每小時加班費
    
            private static decimal extraSubsidies = 5M;//超出基礎加班時間後每小時另加補助費用
    
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime">加班時間</param>
            /// <returns></returns>
            public override decimal CalculateSalary(int overtime)
            {
                decimal actuallySalary = baseSalary+ postSalary;
                if (overtime > baseOvertime)
                {
                    actuallySalary += overtimeSalary * baseOvertime + (overtime - baseOvertime) * (overtimeSalary + extraSubsidies);
                }
                else
                {
                    actuallySalary += overtimeSalary * overtime;
                }
                return actuallySalary;
            }
        }
        /// <summary>
        /// 經理工資計算
        /// </summary>
        public class WagesForManager : AbstractStrategy
        {
            private static decimal baseSalary = 8000;//基礎工資
    
            private static decimal overtimeSalary =80M;//每小時加班費
    
            private static decimal extraOvertimeSalary = 0M;//超出基礎加班時間後每小時加班費
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime">加班時間</param>
            /// <returns></returns>
            public override decimal CalculateSalary(int overtime)
            {
                decimal actuallySalary = baseSalary;
                if (overtime > baseOvertime)
                {
                    actuallySalary += overtimeSalary * baseOvertime + (overtime - baseOvertime) * extraOvertimeSalary;
                }
                else
                {
                    actuallySalary += overtimeSalary * overtime;
                }
                return actuallySalary;
            }
        }
    View Code

總結

優缺點:相對於簡單工廠模式,能避免工廠掛掉,其他相應功能都被牽連的問題;能滿足客戶端高頻率更換功能實現算法要求(不用總是去改工廠類,只需要在客戶端更改調用類)。

策略模式適用於客戶端知道所有的算法或行為的情況,增加了具體功能與客戶端的耦合度。

使用場景:商場計價功能、稅收計算功能、保險行業的參保收益計價功能。

簡單工廠與策略結合

使用簡單工廠時,客戶端需要知道工廠類和功能基類;基本的策略模式,將選擇所用具體實現的職責交給客戶端,本身沒有減除客戶端需要選擇判斷的壓力。能否進優化?可以。將兩者結合起來,讓環境角色(StrategyContext)擁有選擇策略和執行策略兩種功能,客戶端只需要傳遞類型參數調用環境角色即可。

技術分享

基本用法

  1. 技術分享
    /// <summary>
        /// 環境角色
        /// </summary>
        public class Context
        {
            /// <summary>
            /// 需要的策略
            /// </summary>
            private AbstractStrategy strategy = null;
    
            /// <summary>
            /// 獲取策略
            /// </summary>
            /// <returns></returns>
            public Context(int iType)
            {
                switch (iType)
                {
                    case 1:
                        strategy = new WagesForWorkmen();
                        break;
                    case 2:
                        strategy = new WagesForGroupLeader();
                        break;
                    case 3:
                        strategy = new WagesForManager();
                        break;
                }
            }
    
            /// <summary>
            /// 計算實際得到工資
            /// </summary>
            /// <param name="overtime"></param>
            /// <returns></returns>
            public decimal CalculateSalary(int overtime)
            {
                return strategy.CalculateSalary(overtime);
            }
        }
    View Code

總結

優缺點:相對於簡單工廠模式、單一策略模式,進一步實現了解耦(客戶端只需和環境角色交互)。

雖然進一步解耦,但是任然存在簡單工廠的問題。

對設計模式的總結之簡單工廠與策略模式