首页 > 代码库 > 对设计模式的总结之简单工厂与策略模式

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

前言

      面向对象编程追求的本质-提高扩展性、可维护性、灵活性和复用性。合理利用面向对象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

总结

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

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

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