接1.3,本章對“常客積分計算”做類似處理。積分的計算視影片種類而有不同,不過不像收費規則有那麼多變話。看來有理由把積分計算責任放在Rental類身上,首先需要針對“常客積分計算”這部分代碼運用Extract Method(提煉函數)。
再來看局部變量。這裏再一次用到了each,而它可以被當作參數傳入新函數中。另一個臨時變量是frequentRenterPoints。本例中,它在使用之前已經有初始值了,但是提煉出來的函數並沒有讀取該值,所以我們不需要將它當作參數傳遞進去,只需把新函數的返回值累加上去就可行了。
重構前的代碼
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;
}
重構後的代碼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 += each.getFrequentRenterPoints();
// 顯示憑條
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;
}
class Rental...
// 常客積分計算
public int getFrequentRenterPoints(){
if (get_movie().get_priceCode() == Movie.NEW_RELEASE &&
get_dayRented() > 1) {
return 2;
}else{
return 1;
}
}
最終的UML:
去除臨時變量
正如我們之前說的那樣,臨時變量可能是個問題。它們只在自己所屬的函數中有效,所以它們會助長冗長而複雜的函數。這裏有兩個臨時變量,兩者都是用來從Customer對象相關中的Rental對象中獲取某個總量。不論哪個版本的都需要這些總量。我打算運用Replace Temp with Query(以查詢代替臨時變量),並利用查詢函數(querymethod)來取代totalAmount和frequentRentalPoints這兩個臨時變量。由於類中的任何函數都可以調用上述查詢函數,所以它能促成較乾淨的設計,而減少冗長複雜的函數。
首先用Customer類的getTotalCharge()取代totalAmount,由於totalAmount在循環內部被賦值,所以不得不把循環複製到查詢函數中。
class Customer...
public String statement(){
int frequentRenterPoints = 0;//本次總積分
Enumeration<Rental> rentals = _rentals.elements();
// 租賃備案
String result = "Rental Record for "+getName()+"\n";
while(rentals.hasMoreElements()){
Rental each = rentals.nextElement();
frequentRenterPoints += each.getFrequentRenterPoints();
// 顯示憑條
result += "\t"+each.get_movie().get_title()+"\t"+String.valueOf(each.getCharge())+"\n";
}
// 組裝頁腳
result += "Amount owed is "+String.valueOf(getTotalCharge())+"\n";
result += "You earned "+String.valueOf(frequentRenterPoints)+" frequent renter points";
return result;
}
// 計算總金額
public double getTotalCharge(){
double result = 0;
Enumeration<Rental> rentals = _rentals.elements();
while(rentals.hasMoreElements()){
Rental each = rentals.nextElement();
result += each.getCharge();
}
return result;
}
重構後,重新編譯並測試,然後以同樣的手法處理frequentRentalPints。
class Customer...
public String statement(){
Enumeration<Rental> rentals = _rentals.elements();
// 租賃備案
String result = "Rental Record for "+getName()+"\n";
while(rentals.hasMoreElements()){
Rental each = rentals.nextElement();
// 顯示憑條
result += "\t"+each.get_movie().get_title()+"\t"+String.valueOf(each.getCharge())+"\n";
}
// 組裝頁腳
result += "Amount owed is "+String.valueOf(getTotalCharge())+"\n";
result += "You earned "+String.valueOf(getTotalFrequentRenterPoints())+" frequent renter points";
return result;
}
//計算總積分
public int getTotalFrequentRenterPoints(){
int result = 0;
Enumeration<Rental> rentals = _rentals.elements();
while(rentals.hasMoreElements()){
Rental each = rentals.nextElement();
result += each.getFrequentRenterPoints();
}
return result;
}
重新編譯並測試
最終的UML