写在文章之前 一直想读这本书,但总是没有机会寻到,现偶然得到,细细读 来倍感激动,有如当年初读设计模式时的兴奋。独乐乐,不如同乐。 感尚无中文版本,所以小弟不才,翻译与大家同读。此地卧虎藏龙, 英文好我者不胜枚举,若有翻译不妥之处还请见谅。支持者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我们他们的一致性。未 来随着规则的进一步复杂化,我们将很难指出到底那里被改变了,也很 难保证不引入新的错误。 你也许试图作经可能小的改变,毕竟她已经你能够工作。记一句古老的 工程谚语:“如果他自己破了,不要试图去修改她。“这个程序也许没 有破,但是他是有害的。当你发觉他不能适应用户的要求时,它会给你 带来困难。这就是为什么要重构。
提示 当你发现程序的结构不方便增加一个特性,而你不得不给程序增加一个 特性时,重构程序是它容易添加新特性,然后添加你的新 特性. 重构的一步。 待续。。。。。。。。。。。。。。。。。。。。。。。。。。

|