博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

重构:第一个案例

Posted on 2011-06-07 15:07  zhangweia  阅读(242)  评论(0编辑  收藏  举报

       在写重构的学习笔记之前,首先我们需要向伟大的软件设计师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;
    }

}

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