1.4重構-第一章

         接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

 




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章