zoukankan      html  css  js  c++  java
  • 对设计模式的总结之简单工厂与策略模式

    前言

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

    总结

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

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

  • 相关阅读:
    C# Linq to XML
    C# StopWatch
    C# 深拷贝代码
    基础练习 完美的代价
    基础练习 矩形面积交
    基础练习 矩阵乘法 时间限制:1.0s 内存限制:512.0MB
    阶乘计算 高精度
    杨辉三角形 递归与非递归
    数的分解 时间限制:1000 ms | 内存限制:65535 KB 难度:1
    数列排序 sort qsort
  • 原文地址:https://www.cnblogs.com/harveybarray/p/6791679.html
Copyright © 2011-2022 走看看