搬移“金额计算”代码
接1.2,观察amountFor()(计算金额)使用了来自Rental(租赁实体)类的信息,却没有使用来自Customer类的信息。
这就使我们怀疑它是否被放错了位置。绝大多数情况下,函数应该放在它所使用的数据的所属对象内,所以amountFor()应该从Customer(顾客实体)类中移到Rental(租赁实体)类去。
为了这么做,我要运用Move Method(搬移函数)。首先把代码复制到Rental类,调整代码使之适应新家,然后重新编译。
class Rental...
// 计算金额
public double getCharge() {
double result = 0;
switch (get_movie().get_priceCode()) {
case Movie.REGULAR:
result += 2;
if (get_dayRented() > 2) {
result += (get_dayRented() - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
result += get_dayRented() * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if (get_dayRented() > 3) {
result += (get_dayRented() - 3) * 1.5;
}
break;
}
return result;
}
在这个例子里,“适应新家”意味着要去掉参数。此外,还要在搬移的过程中更改函数名称。然后改变Customer.amountFor()函数内容,使它委托调用新的函数即可:
class Customer...
private double amountFor(Rental aRental){
return aRental.getCharge();
}
然后编译并测试,看看有没有破坏什么东西。
接下来找到程序中对于旧函数的引用点,并修改它们,让它们改用新函数。
public String statement(){
double totalAmount = 0;//总金额
int frequentRenterPoints = 0;//本次总积分
Enumeration<Rental> rentals = _rentals.elements();
// 租赁备案
String result = "Rental Record for "+getName()+"\n";
while(rentals.hasMoreElements()){
double thisAmount = 0;
Rental each = rentals.nextElement();
// 计算金额
thisAmount = each.getCharge();
// 常规积分累加
frequentRenterPoints++;
// 特殊新书积分计算
if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&
each.get_dayRented() > 1) {
frequentRenterPoints++;
}
// 显示凭条
result += "\t"+each.get_movie().get_title()+"\t"+String.valueOf(thisAmount)+"\n";
totalAmount += thisAmount;
}
// 组装页脚
result += "Amount owed is "+String.valueOf(totalAmount)+"\n";
result += "You earned "+String.valueOf(frequentRenterPoints)+" frequent renter points";
return result;
}
最终的UML
至此,对于Rental.getCharge()的修改暂时终止,让我们回到Customer.statement()函数。通过观察,发现thisAmount(临时变量-某一类影片的总金额)如今变的多余了。他接受each.getCharge()的执行结果,然后就不会再有任何改变。所以可以运用Replace Temp with Query(以查询取代临时变量)把thisAmount除去:
class Customer...
public String statement(){
double totalAmount = 0;//总金额
int frequentRenterPoints = 0;//本次总积分
Enumeration<Rental> rentals = _rentals.elements();
// 租赁备案
String result = "Rental Record for "+getName()+"\n";
while(rentals.hasMoreElements()){
Rental each = rentals.nextElement();
// 常规积分累加
frequentRenterPoints++;
// 特殊新书积分计算
if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&
each.get_dayRented() > 1) {
frequentRenterPoints++;
}
// 显示凭条
result += "\t"+each.get_movie().get_title()+"\t"+String.valueOf(each.getCharge())+"\n";
totalAmount += each.getCharge();
}
// 组装页脚
result += "Amount owed is "+String.valueOf(totalAmount)+"\n";
result += "You earned "+String.valueOf(frequentRenterPoints)+" frequent renter points";
return result;
}
修改完事,立即编译测试,保证没有破坏任何东西。
临时变量往往会引发问题,他们会导致大量参数被传来传去,而其实完全没有这种必要。当然除去临时变量也会引发问题,如上述修改,会导致查询两次的性能问题,但这个问题可以在Rental中很好的被优化,此处不做说明。