重构:第一个案例

       在写重构的学习笔记之前,首先我们需要向伟大的软件设计师Martin Fowler致敬,是他带给了我们重构的思想,敏捷的思想。

       重构--改善既有代码的设计。意味着对现有运行中的代码进行新的修改、设计。这对很多项目经理来说是不可思议的,因为他们一直奉行的是软件业的一句经典“如果代码可以运行,就不要去修改它”在这条“真理”的引导下,当出现新的功能,新的BUG的时候,后续的程序员总是在原有的基础上修修补补,导致代码越来越庞大,业务逻辑越来越不明了,到最后维护的人员终于看不懂代码逻辑了,程序员开始抓狂了,白头发开始白了,职业病来了,项目死了。曾经在CSDN上流传着这样几个关于代码注释的笑话。1. //这段代码的实现逻辑,作为开发者的我已经不知道为什么这样设计了,请不要试图去理解这段代码并去修改它  2.//如果你试图修改这段代码,但却导致了系统其他地方的BUG,请在下面的计数器上加一,以提醒下一位程序员不要动试图去修改它的念头。

       什么时候我们的代码需要重构了?

        我在看一本UI设计书《写给大家看的设计书》中提到,要学会设计其实很简单,主要是掌握3把斧! a. 你需要知道哪里需要修改   b. 你需要知道该怎么样去修改  c. 实践、动手去修改它。我们学习并利用重构也是一样,首先你的知道代码中的坏味道,其实你的知道怎样去掉这些坏味道,最后动手去修改它。

         首先我们通过一个简单的例子来给大家分享重构的过程和乐趣。题目是这样的:这是一个影片出租店德程序,计算每一位顾客的消费金额并打印详单。操作者告诉程序,顾客租了那些影片,租期多长,程序根据租期多长以及影片的类型算出费用。影片分为三类:普通片、儿童片、新片。除了计算费用外,还要为顾客计算积分,不同类型的积分不同。

        先看一个不优秀的代码设计: 依据题意,我们定义3个类Customer(顾客)  Rental(租赁)  Movice(电影)

image  image image

Customer  类

   1:  public class Customer {
   2:      
   3:      /** 顾客的姓名 **/
   4:      private String name;
   5:      
   6:      public String getName() {
   7:          return name;
   8:      }
   9:   
  10:      /** 租赁的所有影片和租期 **/
  11:      private List rentals = new ArrayList();
  12:      
  13:      public Customer(String _name){
  14:          name = _name;
  15:      }
  16:      
  17:      /** 添加租赁影片的租赁关系 **/
  18:      public void addMovice(Rental _rental){
  19:          rentals.add(_rental);
  20:      }
  21:      
  22:      /** 生成账单 **/
  23:      public void createBill(){
  24:          
  25:          double totalAmount = 0;
  26:          int renterPoint = 0;
  27:          String billInfo = "";
  28:          
  29:          for (Rental _rental : rentals) {
  30:              double thisAmount = 0;
  31:              int thisPoint = 0;
  32:              int type = _rental.getMovice().getType();
  33:              
  34:              switch (type) {
  35:              case Movice.CHILDREN:
  36:                  thisAmount += 2;
  37:                  if(_rental.getDaysRental() > 2){
  38:                      thisAmount += (_rental.getDaysRental() -2) * 1.5;
  39:                  }
  40:                  break;
  41:              case Movice.NEW:
  42:                  thisAmount += _rental.getDaysRental() * 3;
  43:                  break;
  44:              case Movice.NORMAL:
  45:                  thisAmount += 1.5;
  46:                  if(_rental.getDaysRental() > 3){
  47:                      thisAmount += (_rental.getDaysRental() - 3) * 1.5;
  48:                  }
  49:                  break;
  50:              default:
  51:                  break;
  52:              }
  53:              
  54:              thisPoint ++;
  55:              if(type == Movice.NEW && _rental.getDaysRental() > 1){
  56:                  thisPoint ++;
  57:              }
  58:              
  59:              totalAmount += thisAmount;
  60:              renterPoint += thisPoint;
  61:              billInfo += "书名:" +  _rental.getMovice().getName() + "/t" +
  62:                         "价格:" + thisAmount + "/t" + 
  63:                         "积分:" + thisPoint + "/t" + 
  64:                         "天数:" + _rental.getDaysRental() + "/n";
  65:          }
  66:          
  67:          billInfo += "本次总价:" + totalAmount  + "/n" +
  68:                      "本次积分:" + renterPoint;
  69:          
  70:          System.out.println(billInfo);
  71:      }
  72:      
  73:  }

Rental 类

public class Rental {

    /** 租赁的影片 **/
    private Movice movice;
    
    /** 影片的租期 **/
    private int daysRental;
    
    public Rental(Movice _movice,int _daysRental){
        movice = _movice;
        daysRental = _daysRental;
    }
    
    public Movice getMovice() {
        return movice;
    }

    public int getDaysRental() {
        return daysRental;
    }
}
Movic类
public class Movice {

    public static final int NORMAL = 0;
    public static final int CHILDREN = 1;
    public static final int NEW = 2;

    /** 影片的名称 **/
    private String name;
    
    /** 影片的类型**/
    private int type;
    
    public String getName() {
        return name;
    }

    public int getType() {
        return type;
    }

    public Movice(int _type,String _name) {
        name = _name;
        type = _type;
    }
}

朋友们,从上面的代码,你们找到了那些代码的坏味道了?

     1.  Duplicated Code (重复代码):   单我需要创建另外一种账单的打印方式:比如按照XML的格式打印时候,我需要另外写一个函数,然后重复前面获取租赁电影的价钱和积分。

     2. Long Method (过长的方法)  :  Customer类的createBill 功能不单一,方法过长

     3. Customer类过多的魔鬼数字和字符,导致后续的字符和参数的替换不方便

     4. Switch Statements (Switch 惊悚现身): Customer通过Switch来判断影片的类型,随着影片的类型增多,Switch的判断必然增多

     5. 发散式变化 :单我的影片价格调整,积分调整的时候,我需要在Customer生成不同账单的函数中去修改。

     6. 依赖情节 : 这是一种“讲数据和对数据的操作行为包装在一起的技术”,有一种经典的气味是:函数对某个类的兴趣高过对自己所处的类的兴趣。

      7. 语法错误 : 代码语法的漏洞

如果你能发现以上的代码坏味道,甚至更多,那恭喜你,你已经开始进入了重构的大门。接下来我们通过重构来一步步优化代码。请记住:重构代码讲究一小步一小步的修改,测试。不要一开始就对整个结构进行调整,修改。

A. 通过分析代码的坏味道,我们发现第3点:魔鬼数字是最好修改的。替换Customer类中的魔鬼数字得到新的Customer类为:红色部分是我们添加的常量定义,替换到魔鬼数字和字符

   1:  public class Customer01 {
   2:      private String name;
   3:      private static final String BOOKNAME_STRING = "书名:";
   4:      private static final String PRICE_STRING = "价格:";
   5:      private static final String POINT_STRING = "积分:";
   6:      private static final String DAY_STRING = "天数";
   7:      private static final String TOTLEAMOUNT_STRING = "总价格:";
   8:      private static final String TOTLEPOINT_STRING = "总积分";
   9:      private static final String CHAT_T_STRING = "/t";
  10:      private static final String CHAT_N_STRING = "/n";
  11:      
  12:      private static final int MOVICE_CHILDREN_PRICE = 2;
           /** 儿童片租赁后可以使用的天数 **/
  13:      private static final int MOVICE_CHILDREN_DEADLINE = 2;
           /** 超过租赁天数后,应付的价钱 **/
  14:      private static final double MOVICE_CHILDREN_DELAY_PRICE = 1.5;
  15:      
  16:      private static final int MOVICE_NEW_PRICE = 3;
  17:      
  18:      private static final double MOVICE_NORMAL_PRICE = 1.5;        
  19:      private static final int MOVICE_NORMAL_DEADLINE = 3;
  20:      private static final double MOVICE_NORMAL_DEALY_PRICE = 1.5;    
  21:      
  22:      private static final int POINT_ADD_MIN_DAY = 1;
  23:      
  24:      public String getName() {
  25:          return name;
  26:      }
  27:   
  28:      private List rentals = new ArrayList();
  29:      
  30:      public Customer01(String _name){
  31:          name = _name;
  32:      }
  33:      
  34:      public void addMovice(Rental _rental){
  35:          rentals.add(_rental);
  36:      }
  37:      
  38:      
  39:      public void createBill(){
  40:          
  41:          double totalAmount = 0;
  42:          int renterPoint = 0;
  43:          StringBuffer billInfo = new StringBuffer();
  44:          
  45:          for (Rental _rental : rentals) {
  46:              double thisAmount = 0;
  47:              int thisPoint = 0;
  48:              int type = _rental.getMovice().getType();
  49:              
  50:              switch (type) {
  51:              case Movice.CHILDREN:
  52:                  thisAmount += MOVICE_CHILDREN_PRICE;
  53:                  if(_rental.getDaysRental() > MOVICE_CHILDREN_DEADLINE){
  54:                      thisAmount += (_rental.getDaysRental() - MOVICE_CHILDREN_DEADLINE) * MOVICE_CHILDREN_DELAY_PRICE;
  55:                  }
  56:                  break;
  57:              case Movice.NEW:
  58:                  thisAmount += _rental.getDaysRental() * MOVICE_NEW_PRICE;
  59:                  break;
  60:              case Movice.NORMAL:
  61:                  thisAmount += MOVICE_NORMAL_PRICE;
  62:                  if(_rental.getDaysRental() > MOVICE_NORMAL_DEADLINE){
  63:                      thisAmount += (_rental.getDaysRental() - MOVICE_NORMAL_DEADLINE) * MOVICE_NORMAL_DEALY_PRICE;
  64:                  }
  65:                  break;
  66:              default:
  67:                  break;
  68:              }
  69:              
  70:              thisPoint ++;
  71:              if(type == Movice.NEW && _rental.getDaysRental() > POINT_ADD_MIN_DAY){
  72:                  thisPoint ++;
  73:              }
  74:              
  75:              totalAmount += thisAmount;
  76:              renterPoint += thisPoint;
  77:              
  78:              billInfo.append(BOOKNAME_STRING +  _rental.getMovice().getName() + CHAT_T_STRING);
  79:              billInfo.append(PRICE_STRING + thisAmount + CHAT_T_STRING);
  80:              billInfo.append(POINT_STRING + thisPoint + CHAT_T_STRING);
  81:              billInfo.append(DAY_STRING + _rental.getDaysRental() + CHAT_N_STRING);
  82:              
  83:          }
  84:          
  85:          billInfo.append(TOTLEAMOUNT_STRING + totalAmount + CHAT_N_STRING);
  86:          billInfo.append(TOTLEPOINT_STRING + renterPoint + CHAT_N_STRING);        
  87:          System.out.println(billInfo);
  88:      }
  89:  }

   

B. 过长的方法:我们发现Customer类的createBill()方法过长,通过分析该方法后,我们发现该方法主要做了以下几件事情:1. 依次获得单个租赁碟片的价格 2. 依次获得单个碟片的积分 3. 按规程生成账单 因此我们通过抽取业务逻辑形成方法的方式修改Customer类的createBill()方法,同时我们发现String使用的错误,当添加多个字符串的时候,需要使用StringBuffer。结果如下:红色部分为修改的代码

   1:  public class Customer02 {
   2:      private String name;
   3:      private static final String BOOKNAME_STRING = "书名:";
   4:      private static final String PRICE_STRING = "价格:";
   5:      private static final String POINT_STRING = "积分:";
   6:      private static final String DAY_STRING = "天数";
   7:      private static final String TOTLEAMOUNT_STRING = "总价格:";
   8:      private static final String TOTLEPOINT_STRING = "总积分";
   9:      private static final String CHAT_T_STRING = "/t";
  10:      private static final String CHAT_N_STRING = "/n";
  11:      
  12:      private static final int MOVICE_CHILDREN_PRICE = 2;
  13:      private static final int MOVICE_CHILDREN_DEADLINE = 2;
  14:      private static final double MOVICE_CHILDREN_DELAY_PRICE = 1.5;
  15:      
  16:      private static final int MOVICE_NEW_PRICE = 3;
  17:      
  18:      private static final double MOVICE_NORMAL_PRICE = 1.5;        
  19:      private static final int MOVICE_NORMAL_DEADLINE = 3;
  20:      private static final double MOVICE_NORMAL_DEALY_PRICE = 1.5;    
  21:      
  22:      private static final int POINT_ADD_MIN_DAY = 1;
  23:      
  24:      public String getName() {
  25:          return name;
  26:      }
  27:   
  28:      private List rentals = new ArrayList();
  29:      
  30:      public Customer02(String _name){
  31:          name = _name;
  32:      }
  33:      
  34:      public void addMovice(Rental _rental){
  35:          rentals.add(_rental);
  36:      }
  37:      
  38:      /**
  39:       * <获得用户租赁的碟片的价格和积分,生成账单>
  40:       * <1. 获得单个租赁碟片的价格  >
  41:       * <2. 获得单个碟片的积分 >
  42:       * <3. 按规程生成账单>
  43:       */    
  44:   
  45:  private StringBuffer billInfo = new StringBuffer();
  46:      
  47:  public void createBill(){
  48:          
  49:          double totalAmount = 0;
  50:          int renterPoint = 0;
  51:          
  52:          
  53:          for (Rental _rental : rentals) {
  54:                      
  55:              totalAmount += getRentalPrice(_rental);
  56:              renterPoint += getRentalPoint(_rental);;            
  57:              createSingleBill(_rental);            
  58:          }
  59:          
  60:          addStatistics(totalAmount,renterPoint);        
  61:          
  62:  }
  63:      
  64:      private double getRentalPrice(Rental _rental){
  65:          int type = _rental.getMovice().getType();
  66:          double thisAmount = 0;
  67:          
  68:          switch (type) {
  69:          case Movice.CHILDREN:
  70:              thisAmount += MOVICE_CHILDREN_PRICE;
  71:              if(_rental.getDaysRental() > MOVICE_CHILDREN_DEADLINE){
  72:                  thisAmount += (_rental.getDaysRental() - MOVICE_CHILDREN_DEADLINE) * MOVICE_CHILDREN_DELAY_PRICE;
  73:              }
  74:              break;
  75:          case Movice.NEW:
  76:              thisAmount += _rental.getDaysRental() * MOVICE_NEW_PRICE;
  77:              break;
  78:          case Movice.NORMAL:
  79:              thisAmount += MOVICE_NORMAL_PRICE;
  80:              if(_rental.getDaysRental() > MOVICE_NORMAL_DEADLINE){
  81:                  thisAmount += (_rental.getDaysRental() - MOVICE_NORMAL_DEADLINE) * MOVICE_NORMAL_DEALY_PRICE;
  82:              }
  83:              break;
  84:          default:
  85:              break;
  86:          }
  87:          return thisAmount;
  88:      }
  89:      
  90:      private int getRentalPoint(Rental _rental){
  91:          int thisPoint = 0;
  92:          thisPoint ++;
  93:          if(_rental.getMovice().getType() == Movice.NEW && _rental.getDaysRental() > POINT_ADD_MIN_DAY){
  94:              thisPoint ++;
  95:          }
  96:          return thisPoint;
  97:      }
  98:   
  99:      private void createSingleBill(Rental _rental){
 100:          billInfo.append(BOOKNAME_STRING +  _rental.getMovice().getName() + CHAT_T_STRING);
 101:          billInfo.append(PRICE_STRING + getRentalPrice(_rental) + CHAT_T_STRING);
 102:          billInfo.append(POINT_STRING + getRentalPoint(_rental) + CHAT_T_STRING);
 103:          billInfo.append(DAY_STRING + _rental.getDaysRental() + CHAT_N_STRING);
 104:      }
 105:      
 106:      private void addStatistics(double totalAmount,int renterPoint){
 107:          billInfo.append(TOTLEAMOUNT_STRING + totalAmount + CHAT_N_STRING);
 108:          billInfo.append(TOTLEPOINT_STRING + renterPoint + CHAT_N_STRING);
 109:          System.out.println(billInfo);
 110:      }
 111:   
 112:  }

C.  依赖情节,我们发现getRentalPrice(),getRentalPoint()都和租赁有关,和顾客没有关系,因为我们需要把其移到对应的类中去,修改为Customer类以及Rental类为:

public class Customer03 {
    private String name;
    private static final String BOOKNAME_STRING = "书名:";
    private static final String PRICE_STRING = "价格:";
    private static final String POINT_STRING = "积分:";
    private static final String DAY_STRING = "天数";
    private static final String TOTLEAMOUNT_STRING = "总价格:";
    private static final String TOTLEPOINT_STRING = "总积分";
    private static final String CHAT_T_STRING = "/t";
    private static final String CHAT_N_STRING = "/n";
    

    
    public String getName() {
        return name;
    }

    private List rentals = new ArrayList();
    
    public Customer03(String _name){
        name = _name;
    }
    
    public void addMovice(Rental03 _rental03){
        rentals.add(_rental03);
    }
    
    /**
     * <获得用户租赁的碟片的价格和积分,生成账单>
     * <1. 获得单个租赁碟片的价格  >
     * <2. 获得单个碟片的积分 >
     * <3. 按规程生成账单>
     */    

private StringBuffer billInfo = new StringBuffer();
    
public void createBill(){
        
        double totalAmount = 0;
        int renterPoint = 0;
                
        for (Rental03 _rental : rentals) {
                    
            totalAmount += _rental.getRentalPrice();
            renterPoint += _rental.getRentalPoint();;            
            createSingleBill(_rental);            
        }
        
        addStatistics(totalAmount,renterPoint);        
        
    }
    
    private void createSingleBill(Rental03 _rental){
        billInfo.append(BOOKNAME_STRING +  _rental.getMovice().getName() + CHAT_T_STRING);
        billInfo.append(PRICE_STRING + _rental.getRentalPrice() + CHAT_T_STRING);
        billInfo.append(POINT_STRING + _rental.getRentalPoint() + CHAT_T_STRING);
        billInfo.append(DAY_STRING + _rental.getDaysRental() + CHAT_N_STRING);
    }
    
    private void addStatistics(double totalAmount,int renterPoint){
        billInfo.append(TOTLEAMOUNT_STRING + totalAmount + CHAT_N_STRING);
        billInfo.append(TOTLEPOINT_STRING + renterPoint + CHAT_N_STRING);
        System.out.println(billInfo);
    }

}

Rental 类修改:

public class Rental03 {

    private Movice movice;
    private int daysRental;
    
    private static final int MOVICE_CHILDREN_PRICE = 2;
    private static final int MOVICE_CHILDREN_DEADLINE = 2;
    private static final double MOVICE_CHILDREN_DELAY_PRICE = 1.5;
    
    private static final int MOVICE_NEW_PRICE = 3;
    
    private static final double MOVICE_NORMAL_PRICE = 1.5;        
    private static final int MOVICE_NORMAL_DEADLINE = 3;
    private static final double MOVICE_NORMAL_DEALY_PRICE = 1.5;    
    
    private static final int POINT_ADD_MIN_DAY = 1;
    
    public Rental03(Movice _movice,int _daysRental){
        movice = _movice;
        daysRental = _daysRental;
    }
    
    public Movice getMovice() {
        return movice;
    }

    public int getDaysRental() {
        return daysRental;
    }
    public double getRentalPrice(){
        int type = getMovice().getType();
        double thisAmount = 0;
        
        switch (type) {
        case Movice.CHILDREN:
            thisAmount += MOVICE_CHILDREN_PRICE;
            if(getDaysRental() > MOVICE_CHILDREN_DEADLINE){
                thisAmount += (getDaysRental() - MOVICE_CHILDREN_DEADLINE) * MOVICE_CHILDREN_DELAY_PRICE;
            }
            break;
        case Movice.NEW:
            thisAmount += getDaysRental() * MOVICE_NEW_PRICE;
            break;
        case Movice.NORMAL:
            thisAmount += MOVICE_NORMAL_PRICE;
            if(getDaysRental() > MOVICE_NORMAL_DEADLINE){
                thisAmount += (getDaysRental() - MOVICE_NORMAL_DEADLINE) * MOVICE_NORMAL_DEALY_PRICE;
            }
            break;
        default:
            break;
        }
        return thisAmount;
    }
    
    public int getRentalPoint(){
        int thisPoint = 0;
        thisPoint ++;
        if(getMovice().getType() == Movice.NEW && getDaysRental() > POINT_ADD_MIN_DAY){
            thisPoint ++;
        }
        return thisPoint;
    }
}

D. 我们发现Rental类的getRentalPrice() 跟影片的类型和影片的价格有关,因此其更应该放到Movice类里面去,修改Rental类和Movice类为。通过迁移,租赁价格的修改都集中到了Movice类中。

public class Rental05 {

    private Movice05 movice;
    private int daysRental;


    
    private static final int POINT_ADD_MIN_DAY = 1;
    
    public Rental05(Movice05 _movice,int _daysRental){
        movice = _movice;
        daysRental = _daysRental;
    }
    
    public Movice05 getMovice() {
        return movice;
    }

    public int getDaysRental() {
        return daysRental;
    }
    
     public double getRentalPrice(){        
        return getMovice().getTotalPrice(getDaysRental());
    }
    
    public int getRentalPoint(){
        int thisPoint = 0;
        thisPoint ++;
        if(getMovice().getType() == Movice.NEW && getDaysRental() > POINT_ADD_MIN_DAY){
            thisPoint ++;
        }
        return thisPoint;
    }
}

Movice类

public class Movice05 {

    public static final int NORMAL = 0;
    public static final int CHILDREN = 1;
    public static final int NEW = 2;

    private static final int MOVICE_CHILDREN_PRICE = 2;
    private static final int MOVICE_NEW_PRICE = 3;    
    private static final double MOVICE_NORMAL_PRICE = 1.5;
    
    private static final int MOVICE_CHILDREN_DEADLINE = 2;
    private static final double MOVICE_CHILDREN_DELAY_PRICE = 1.5;    
    
    private static final int MOVICE_NORMAL_DEADLINE = 3;
    private static final double MOVICE_NORMAL_DEALY_PRICE = 1.5;
    
    private String name = "";
    private int type = 0;
    private int thisAmount = 0;
    
    public int getTotalPrice(int daysRental) {
        if(getType() == CHILDREN){
            thisAmount += MOVICE_CHILDREN_PRICE;
            if(daysRental > MOVICE_CHILDREN_DEADLINE){
                thisAmount += (daysRental - MOVICE_CHILDREN_DEADLINE) * MOVICE_CHILDREN_DELAY_PRICE;
            }
        }else if(getType() == NORMAL){
            thisAmount += MOVICE_NORMAL_PRICE ;
            if(daysRental > MOVICE_NORMAL_DEADLINE){
                thisAmount += (daysRental - MOVICE_NORMAL_DEADLINE) * MOVICE_NORMAL_DEALY_PRICE;
            }
        }else if(getType() == NEW){
            thisAmount += MOVICE_NEW_PRICE * daysRental;
        }
        return thisAmount;
    }

    public String getName() {
        return name;
    }

    public int getType() {
        return type;
    }

    public Movice05(int _type,String _name) {
        name = _name;
        type = _type;
    }
}

D. 到这里,我们发现惊悚的Switch类还没有处理掉。通过我们分析Switch主要是对不同的电影类型进行不同的处理,因此我们可以考虑抽取一个超级的电影类,不同的电影类型继承该类来解决Switch的问题。

public abstract class MoviceSuper {
    
    /** 影片的价格 **/
    public int price ;
    
    /** 影片的积分 **/
    public int point;
    
    /** 一步影片可以租多少天 **/
    public int rentalFreeDays;
    
    /** 超过租期了付的价钱**/
    public double delayDayPrice ;
    
    /** 电影的名称**/
    public String name;
    
    public String getName() {
        return name;
    }

    public MoviceSuper(String _name){
        name = _name;
    }
    
    /**
     * <获得租赁影片的价钱>
     * <总价格 = 单个影片的价格 + 延迟时每天应付的价格>
     * 
     * @param daysRental :租赁的天数
     * @return
     */
    public abstract double getRentalPrice(int daysRental);
    
    public abstract int getRentalPoint();
}

package com.chapter01;

public class MoviceChild extends MoviceSuper{

    private static final int POINT = 1;
    private static final int PRICE = 2;
    private static final int DEADLINE = 2;
    private static final double DELAY_PRICE = 1.5;
    
    public MoviceChild(String name) {
        super(name);
        // TODO Auto-generated constructor stub
        price = PRICE;
        
        rentalFreeDays = DEADLINE;
        
        delayDayPrice = DELAY_PRICE;
        
        point = POINT;
    }

    @Override
    public int getRentalPoint() {
        // TODO Auto-generated method stub
        return point;
    }

    @Override
    public double getRentalPrice(int daysRental) {
        // TODO Auto-generated method stub
        double thisAmount = 0;
        thisAmount += price;
        if(daysRental > rentalFreeDays){
            thisAmount += (daysRental - rentalFreeDays) * delayDayPrice;
        }
        return thisAmount;
    }

}
package com.chapter01;

public class MoviceNew extends MoviceSuper{

    private static final int PRICE = 3;    
    
    private static final int POINT = 2;
    
    public MoviceNew(String name) {
        super(name);
        
        price = PRICE;
        
        delayDayPrice = PRICE;
        
        rentalFreeDays = 0;
        
        point = POINT;
    }

    @Override
    public int getRentalPoint() {
        // TODO Auto-generated method stub
        return point;
    }

    @Override
    public double getRentalPrice(int daysRental) {
        // TODO Auto-generated method stub
        
        return daysRental * price;
    }

}
package com.chapter01;

public class MoviceNormal extends MoviceSuper{

    private static final int PRICE = 2;
    
    private static final int DEADLINE = 3;
    
    private static final double DEALY_PRICE = 1.5;
    
    private static final int POINT = 1;
    
    public MoviceNormal(String name) {
        super(name);
        
        price = PRICE;
        
        delayDayPrice = DEALY_PRICE;
        
        rentalFreeDays = DEADLINE;
        
        point = POINT;
    }

    @Override
    public int getRentalPoint() {
        // TODO Auto-generated method stub
        return point;
    }

    @Override
    public double getRentalPrice(int daysRental) {
        double thisAmount = 0;
        thisAmount += price ;
        if(daysRental > price){
            thisAmount += (daysRental - price) * delayDayPrice;
        }
        return thisAmount;
    }

}

通过我们一小步一小步的重构,让我们的程序更加优美,适应变化性更强。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《重构:改善既有代码的设计第2版pdf》是一本由Martin Fowler撰写的软件工程经典之作,讲述了如何通过重构来改善既有代码的设计质量,提高软件系统的可读性、可维护性和可扩展性。这本书详细阐述了重构的原则、实践、技巧和案例,对软件开发人员、架构师和工程师都是非常有益的参考书籍。 重构是一种旨在在不改变软件系统外部行为的前提下修改代码内部结构的技术。通过重构可以消除代码中的重复、提取公共代码、改进函数和类的接口、消除魔法数字和硬编码等不良实践,使代码更加简洁、可读、可维护、可扩展,从而提高软件系统的质量。这本书中提出了多种重构技术,包括重命名、提炼函数、搬移函数、拆分类、合并类等等。通过实际案例的演示,读者可以深入理解每个技术的应用场景,以及如何正确地使用。 此外,《重构:改善既有代码的设计第2版pdf》还介绍了如何在重构时保持代码的正确性和完整性。它详细阐述了测试驱动重构的思想和技术,以及如何使用测试来验证所做的重构是否正确和有效。同时,该书还讲解了如何使用重构来应对软件设计中的问题和挑战,如代码坏味道、代码膨胀、复杂度过高等等。通过阅读本书,读者可以获得许多实用技巧和经验,从而更好地应对日常编码工作中的实际问题。 总之,《重构:改善既有代码的设计第2版pdf》是一本非常优秀的软件工程书籍,它提供了很多实用的技巧和经验,对于想要提高编码水平、提高软件系统质量的人员都是非常有价值的参考。 ### 回答2: 《重构:改善既有代码的设计第2版pdf》是一本非常有价值的书籍,它提供了许多关于重构和代码设计方面的实用技巧和建议。在开发软件时,我们通常会遇到需要改进代码的情况,而本书就为我们提供了一些重构代码的方法和原则。 本书的作者Martin Fowler强调了“渐进式重构”的概念,即在不改变系统行为的前提下,逐步改进代码。这样做可以降低风险,同时提高代码质量。他还强调了代码的“坏味道”,指的是代码中常见的一些问题,例如代码冗余、过长的方法或类等,这些问题会导致代码难以维护。 本书还介绍了一些常见的重构技术,例如提炼函数、合并重复的代码、使用多态等。这些技术可以帮助我们改进代码的设计,提高系统的健壮性和可维护性。 总的来说,《重构:改善既有代码的设计第2版pdf》是一个非常有用的书籍,可以帮助软件开发人员更好地重构和改进代码,并提高系统的可维护性和健壮性。通过印刷品将其的阅读体验最佳。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值