• 必会重构技巧(四):提取工厂类


    提取工厂类:使用一个简单工厂类来新建对象实例。

      举例理解:对于一个客户端事件,我们可能需要初始化一个对象实例,并调用其中的几个方法做一系列的操作。如果客户端事件经常需要扩展,那可能每次初始化的对象实例可能都是不同的,那么为了把这个初始化对象的动作封装起来,为了使这个行为更加便于维护,我们就需要把初始化对象的动作交给简单工厂类来统一完成。

      项目实例:做过一个小型的购物商城。其中有个需求简述如下:管理员可以通过后台自助增删改当前商品的打折比例和打折类型。一开始我们想的都很简单,以为用户仅仅是打折而已,OK,加个下拉列表然后里面放上1-9折就行了,然后售价X这个折数就好了。想不到设计好后,当时就被驳回了,客户说我们不仅仅会打折,可能还会返点。客户的需求向来是多变的,不能要求需求不变,那只有在设计上改变了。先看看现在项目中的设计吧,具体代码忘了,下面的代码大部分引自博客园上一大牛的文章,因为情况差不多,引来用一下,说明道理就好了。


      另注:简单工厂应对一些简单逻辑比较适用,并不适合一些逻辑比较复杂的应用。
      下面直接贴出经过重构的代码:

    相关抽象类

    abstract class SuperCash
    {
      public abstract double0;"> ReturnTotalCash(double money);
    }
    class NormalCash : SuperCash
    {
      public override double ReturnTotalCash(double money)
      {
        return money;
      }
    }
    class RebateCash : SuperCash
    {
      private double moneyRebate = 1d;
      public RebateCash(double _mRebate)
      {
        moneyRebate = _mRebate;
      }

      public override double ReturnTotalCash(double money)
      {
        return money * moneyRebate;
      }
    }
    class ReturnCash : SuperCash
    {
      private double moneyCondition = 0.0d;
      private double moneyReturn = 0.0d;
      public ReturnCash(double _mCondition, double _mReturn)
      {
        moneyCondition = _mCondition;
        moneyReturn = _mReturn;
      }

      public override double ReturnTotalCash(double money)
      {
        if (money > moneyCondition)
        {
          return money - moneyReturn;
        }
        return money;
      }
    }

    现金消费工厂

    class CashFactory
    {
      public static SuperCash CreateSuperCash(string type)
      {
        SuperCash superCash = null;
        switch (type)
        {
          case "Normal":
            superCash = new NormalCash();
            break;
          case "80% Off":
            superCash = new RebateCash(0.8);
            break;
          case "50% Off":
            superCash = new RebateCash(0.5);
            break;
          case "100 Per 300":
            superCash = new ReturnCash(300, 100);
            break;
        }
        return superCash;
      }
    }

    调用的事件

    protected void btnTotal_Click(object sender, EventArgs e)
    {
      string type = ddlType.SelectedItem.Value;
      SuperCash superCash = CashFactory.CreateSuperCash(type);
      double total = superCash.ReturnTotalCash(Convert.ToDouble(txtPrice.Text)*Convert.ToDouble(txtNum.Text));
      lbTotal.Text = total.ToString();
    }

      看看上面的代码,仔细想想,发现为了增加一个打折,还是需要修改后台代码,修改部分如下:
      (1)需要在客户前端的DropDownList中加入新打折方案
      (2)需要修改Cashfactory工厂类
      (3)需要增加一个对应的实现了接口的打折方法
     
     
      那如何才能省掉这三步呢?如何让我们仅仅通过配置就可以搞定这一切呢?对应的修改方案如下:
      (1)使用Xml代替硬编码,DropDownList读取Xml绑定数据。
      (2)在工厂类中,运用反射获取,初始化并返回实例对象。
      (3)如果确定了商品价格可能出现的类型,比如只有三种情况a:正常价格;b:打折;c:买多少返利多少,那么我们基本可以做到只用修改配置文件就可以实现修改用户的需求了。
     
      下面的代码不写了,各位有兴趣可以试试。
  • 相关阅读:
    2019-08-10T12:18:27.745963Z 7 [Note] Slave I/O thread for channel '': connected to master 'repl_user@192.168.43.81:3306',replication started in log 'mysql-bin.000001' at position 154 2019-08-10T12:18:
    yum安装的mysql 目录结构
    Starting MySQL.. ERROR! The server quit without updating PID file (/db/data/110.pid).
    CentOS7修改主机名
    使用ssh登陆远程主机
    traceroute命令
    Linux设置开机启动
    检查是否安装服务包
    CSS之盒子模型
    BFC块级格式化上下文
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/2892669.html
Copyright © 2020-2023  润新知