上篇文章说了,类做回自己的事
上一篇文章:java 代码重构-第一章(类自己该做自己的事)
下一篇文章:java 代码重构-第一章(去除临时变量)
提炼「常客积点计算」代码
下一步要对「常客积点计算」做类似处理。点数的计算视影片种类而有不同,不过不像收费规则有那么多变化。看来似乎有理由把积点计算责任放在Rental class 身上。首先我们需要针对「常客积点计算」这部分代码(以下粗体部分)运用 Extract Method 重构准则。
再一次我又要寻找局部变量。这里再一次用到了each ,而它可以被当作参数传入新函数中。另一个临时变量是frequentRenterPoints。本例中的它在被使用之前已经先有初值,但提炼出来的函数并没有读取该值,所以我们不需要将它当作参数传进去,只需对它执行「附添赋值动作」(appending assignment,operator+=)就行了。
我完成了函数的提炼,重新编译并测试;然后做一次搬移,再编译、再测试。重构时最好小步前进,如此一来犯错的几率最小。
好,下面来代码了 Customer
/** * 通计清单 * * @return */ public String statement() { double totalAmount = 0;// 合计 int frequentRentePoints = 0; Enumerationenu_rentals = rentals.elements(); String result = "Rental Record for " + this.getName() + " \n"; while (enu_rentals.hasMoreElements()) { double thisAmount = 0; Rental each = enu_rentals.nextElement(); thisAmount = each.getCharge();// 计算一笔租片费 frequentRentePoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) { frequentRentePoints++; } result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n"; totalAmount += thisAmount; } result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRentePoints) + " frequent renter points"; return result; }
看到段代码吗?
frequentRentePoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) { frequentRentePoints++; }
我们要把这段代码提炼出去,好,那么我们的代码变成这样
首先我们在Rental里添加方法
package com.mkfree.refactoring.shap1; /** * 租凭 * * @author hk * * 2012-12-25 下午10:57:00 */ public class Rental { /** * * @return */ int getFrequentRenterPoints() { if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1) return 2; else return 1; } }
然后在customer 里 Statment方法调用,看下面代码
/** * 通计清单 * * @return */ public String statement() { double totalAmount = 0;// 合计 int frequentRentePoints = 0; Enumerationenu_rentals = rentals.elements(); String result = "Rental Record for " + this.getName() + " \n"; while (enu_rentals.hasMoreElements()) { double thisAmount = 0; Rental each = enu_rentals.nextElement(); thisAmount = each.getCharge();// 计算一笔租片费 /* * 刚刚把代码提炼,现在注释起来 frequentRentePoints++; * * if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && * each.getDaysRented() > 1) { frequentRentePoints++; } */ frequentRentePoints += each.getFrequentRenterPoints(); result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n"; totalAmount += thisAmount; } result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRentePoints) + " frequent renter points"; return result; }
我利用重构前后的UML(Unified Modeling Language ,统一建模语言)图形(图1.4 至图1.7〕总结刚才所做的修改。
修改前的uml
修改后的um
l
那么最后的代码
Customer
package com.mkfree.refactoring.shap1; import java.util.Enumeration; import java.util.Vector; /** * 顾客 * * @author hk * * 2012-12-25 下午10:59:03 */ public class Customer { private String name; private Vectorrentals = new Vector<>(); public Customer(String name) { this.name = name; } /** * 添加 * * @param rental */ public void addRentals(Rental rental) { rentals.add(rental); } public String getName() { return name; } /** * 通计清单 * * @return */ public String statement() { double totalAmount = 0;// 合计 int frequentRentePoints = 0; Enumerationenu_rentals = rentals.elements(); String result = "Rental Record for " + this.getName() + " \n"; while (enu_rentals.hasMoreElements()) { double thisAmount = 0; Rental each = enu_rentals.nextElement(); thisAmount = each.getCharge();// 计算一笔租片费 /* * 刚刚把代码提炼,现在注释起来 frequentRentePoints++; * * if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && * each.getDaysRented() > 1) { frequentRentePoints++; } */ frequentRentePoints += each.getFrequentRenterPoints(); result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n"; totalAmount += thisAmount; } result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRentePoints) + " frequent renter points"; return result; } }
Rental 类
package com.mkfree.refactoring.shap1; /** * 租凭 * * @author hk * * 2012-12-25 下午10:57:00 */ public class Rental { private Movie movie; private int daysRented; public Rental(Movie movie, int daysRented) { this.movie = movie; this.daysRented = daysRented; } public Movie getMovie() { return movie; } public int getDaysRented() { return daysRented; } double getCharge() { double result = 0; switch (getMovie().getPriceCode()) { case Movie.REGULAR: result += 2; if (getDaysRented() > 2) result += (getDaysRented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += getDaysRented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (getDaysRented() > 3) result += (getDaysRented() - 3) * 1.5; break; } return result; } /** * * @return */ int getFrequentRenterPoints() { if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1) return 2; else return 1; } }
Movie
package com.mkfree.refactoring.shap1; /** * 电影类 * @author hk * * 2012-12-25 下午10:55:14 */ public class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String title; private int priceCode; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getPriceCode() { return priceCode; } public void setPriceCode(int priceCode) { this.priceCode = priceCode; } }
最后是调用的Client
package com.mkfree.refactoring.shap1; import org.junit.Test; public class Client { @Test public void testStatement() { Movie movie1 = new Movie(); movie1.setTitle("少林足球"); movie1.setPriceCode(1); Rental rental1 = new Rental(movie1, 2); Movie movie2 = new Movie(); movie2.setTitle("大话西游"); movie2.setPriceCode(2); Rental rental2 = new Rental(movie2, 3); Customer customer = new Customer("oyhk"); customer.addRentals(rental1); customer.addRentals(rental2); String statement = customer.statement(); System.out.println(statement); } }
好了,代码提炼完了...你们有什么感觉...