对设计模式的总结之简单工厂与策略模式

前言

      面向对象编程追求的本质-提高扩展性、可维护性、灵活性和复用性。合理利用面向对象6个原则,能够很好的达到要求。如何利用好就是至关重要的了,前人总结了23+个设计模式能够让初学者更容易学到其中的精髓,本文就说说我对本人对简单工厂模式、策略模式的见解。

设计模式链接

  1. 对设计模式的总结之原则

  2. 对设计模式的总结之简单工厂与策略模式
  3. 对设计模式的总结之装饰模式与代理模式

  4. 对设计模式的总结之工厂方法模式和抽象工厂模式

简单工厂模式与策略模式

简单工厂模式

      工作中,常常遇到需要做一个功能(鸭子),这个功能中含有可控个数的子操作功能(鸭子叫,鸭子跑,鸭子飞),而且子功能在不同的情况下处理方式又不相同(成年鸭子/小鸭子叫,成年鸭子/小鸭子跑,成年鸭子/小鸭子飞)。我们首先就会想到,用简单工厂模式哇。创建一个该功能的抽象基类,再创建多个实现不同逻辑的子类继承它。最后建立一个工厂类,通过工厂类中类型判断可生成不同的该功能子类实例。客户端最后调用工厂和抽象基类操作即可。实现类与类松耦合,既简单又实用。

      功能需求:统一登录系统登录或登出不同的游戏。1、登录系统是统一的;2、固定两个功能-登录和登出;3、有限个游戏。

      

基本用法

  1.      //选取具体产品,返回实例
         var gameOfInteractive = GameOfInteractive.GameService(1);
         //调用方法
         gameOfInteractive.Login("sLoginName", "sPsw");
    
    
        /// <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、只做工资计算,返回最终实得工资。2、有限个工种。3、后期可能还会添加新的工种。

      

基本用法

  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

总结

      优缺点:相对于简单工厂模式、单一策略模式,进一步实现了解耦(客户端只需和环境角色交互)。

                 虽然进一步解耦,但是任然存在简单工厂的问题。

posted on 2017-05-07 22:16  LuoDad  阅读(650)  评论(1编辑  收藏  举报