搬移“金額計算”代碼
接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中很好的被優化,此處不做說明。