重构--refactoring(1)

      写在文章之前
     一直想读这本书,但总是没有机会寻到,现偶然得到,细细读
来倍感激动,有如当年初读设计模式时的兴奋。独乐乐,不如同乐。
感尚无中文版本,所以小弟不才,翻译与大家同读。此地卧虎藏龙,
英文好我者不胜枚举,若有翻译不妥之处还请见谅。支持者UP一下
即可。
     
     
      第一章: 重构,第一个例子
     该如何开始写重构这本书呢?传统的方式是列出历史提纲、广
泛的原则等。当一些人在会议上开始这么做的时候,我则有些轻微的
睡意。面对讲演者      的陈词滥调我的头脑开始思考在较低层次的
处理上,直到她或他给出一个例子。      这将把我从昏昏欲睡中唤
醒,有一个例子能够使我知道下一步该干什么.用原理,太简单以至
于一般化,太难了很难指出该如何应用。而一个例子将会使问题变得
更清晰。
因此,我打算从一个重构的例子开始本书。在这个过程中,我将告诉
你如何重构以及让你对重构处理一个感性的认识。这样接下来能让我
提供一个通常的原理风格上的介绍。
然而,随着一个例子的引入,我将碰上一个一个大问题。如果我选择
一个大程序,描述她如何重构,这对于打多数的读者来说过于复杂以
至于不能完成工作。(我尝试后发觉即便是一个轻微复杂的例子也超
过100页)另一方面,如果我选择一个容易被理解的小程序,那会使
得重构看起来没有价值。
因此,我将使用经典著作中的方式通过引入一个真实世界中的程序来
描述这门技术。坦白的说,我展示给你的一段我打算使用的小程序对
她重构是没有什么价值的,但是如果我展示给你的是一个大系统中的
一段代码,那么重构不久将变得重要。所以我不得不要求你将它看作
是一个大系统中的一部分。
开始点
程序非常简单。他计算并打印一名客户在录像带出租店的收费情况。
程序输入客户借阅的电影和借阅时间。通过借阅的日期长度和借阅的
电影类型来计算收费。这儿有三种类型的影片:通常、儿童、新片。
另外通过计算费用,可以估租借热点,不在依赖于电影是否是新版。
下面几个类将代表不同的元素,类图如下所示:
图1.1 开始点得类图,仅最重要的特性被描述。使用UML符号。

我将轮流展示这些类的代码。
Movie
Movie 是一个简单得类。

public class Movie{
  public static final int SHILDRENS =2;
  public static final int REGULAR =0;
  public static final int NEW_RELEASEE =1;
 
  private String _title ;
  private int _priceCode ;
 
  public Movie(String title,int priceCode){
    _title = title ;
    _priceCode = priceCode;
  }
 
  public int getPriceCode(){
    return _priceCode;
  }
 
  public void setPriceCode(int arg){
    _priceCode = arg;
  }
 
  public void getTitle(){
    return _title;
  }
}

Rental
Rental 代表一个客户借一部电影
class Rental {
  private Movie _movie;
  private int _daysRented;
 
  public Rental(Movie movie,int daysRented){
    _movie = movie;
    _daysRented = daysRented;
  }
 
  public int getDaysRented(){
    return _daysRented;
  }
 
  public Movie getMovie(){
    return _movie;
  }
}

Customer
Customer 代表录像店的一个客户,像其她的类一样她也有所数据和访问器。
class Customer{
  private String _name;
  private Vector _rentals = new Vector();
 
  public Customer(String name){
    _name = name;
  }
 
  public void addRental(Rental arg){
  _rentals.addElement(arg);
  }
 
  public String getName(){
    return _name;
  }
}

Customer有一个方法实现 statement(收费情况)。图:1.2表明了这些方法
的交互。这个方法的主体是一个界面。
图1.2statement 方法的交互图。

public String statement(){
  double totalAmount =0;
  int frequentRenterPoints =0;
  Enumeration rentals = _rentals.elements();
  String result ="Rental Record for "+getName()+"/n";
  while(rentals.hasMoreElements()){
    double thisAmount =0;
    Rental each = (Rental)rentals.nextElement();
   
    switch(each.getMovie().getPriceCode()){
      case Movie.REGULAR:
        thisAmount+=2;
        if(each.getDaysRented()>2)
        thisAmount+=(each.getDaysRented()-2)*1.5;
        break;
      case Movie.NEW_RELEASE:
        thisAmount+=each.getDaysRented()*3;
        break;
      case Movie.CHILDRENS:
        thisAmount+=1.5;
        if(each.getDaysRented()>3)
          thisAmount+=(each.getDaysRented()-3)*1.5;
          break;
     }
    
     frequentRenterPoints++;
     if((each.getMovie.getPriceCode()==Movie.NEW_RELEASE)&&       
           each.getDaysRented()>1)
     frequentRenterPoints++;
    
     //show figures for this rental
     result+="/t"each.getMOVIE().getTitle()+"/t"+
              String.valueOf(thisAmount)+"/n";
   
    totalAmount +=  thisAmount;
   
    }               
           
    //add footer lines     
    result+="Amount owed is "+  String .valueOf(totalAmount)+"/n";
    result+="You earned "+String.valueOf(frequentRenterPoints)+
          "frequent renter points";
   
    return result;
    }
 
 
关于这个程序
  你对这个程序设计有什么印象?我对他的看法是他不是一个好的设计
并且也不是面向对象的。对于一个像这样的简单程序来说,这并不重要。
作为一个敏捷和不清晰的简单例子来说本身没有任何错误。但是如果这
是一个大系统的一部分,那么这个程序会有一些问题。statemetn 方
法在Customer类中走得太远了。许多工作因该在其他类中来做。
即便程序能够工作。你是否愿意对丑陋的代码作美化呢?还是直到我们
改变系统。编译器是不会知道代码是否丑陋或清晰。当时当我改变一个
系统的时候,我们将卷入到系统中,我们会注意到这一点。一个糟糕的
设计很难被改变,因为很难指出到底那里需要被改变。如果难于指出要
改变什么,那么程序员将会犯错误或是引入新的BUG。

在这个例子中,我们将转变用户的想法。首先:用户想能够在WEB
上发布有关资费信息以满足客户的抱怨。考虑到这种改变,你要查看
你的源代码,看看是否有可能重用你的当前statement 方法的行为来
满足HTMLStatement。你唯一可行的方法是重新写具有相同特性的整
个方法,当然,这并不费力气,通过拷贝粘贴即可实现你的要求。
但是当收费规则改变呢?你不得不修改statement和HTMLStatement,以
确保他们在一致。问题是当以后再一次改变时,你不得不再一次拷贝很
粘贴代码。如果你期望你的程序不会再被改动,那么拷贝很粘贴是不错
的方法,但如果你的程序未来会被修改,那么拷贝很粘贴将带来混乱。

我们来介绍第二种改变。用户想法变电影分类方法,但是他们无法立即
决定下来,而是留待以后再决定。他们对此头脑中有一个想法。这些改
变将影响到出租方式、出租频率点数的计算。作为一个有经验的开发人
员,你应当更当上用户的计划,而
不是让你的计划停留在6个月内。
statement方法应该能够应付对于非类方法和收费规则的改变。但如果我
采取从statemet方法拷贝很粘贴到HTMLStatemtn我们他们的一致性。未
来随着规则的进一步复杂化,我们将很难指出到底那里被改变了,也很
难保证不引入新的错误。

你也许试图作经可能小的改变,毕竟她已经你能够工作。记一句古老的
工程谚语:“如果他自己破了,不要试图去修改她。“这个程序也许没
有破,但是他是有害的。当你发觉他不能适应用户的要求时,它会给你
带来困难。这就是为什么要重构。
提示
  
当你发现程序的结构不方便增加一个特性,而你不得不给程序增加一个
特性时,重构程序是它容易添加新特性,然后添加你的新
特性.
重构的一步。
待续。。。。。。。。。。。。。。。。。。。。。。。。。。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值