面向?qū)ο筌浖_發(fā)的敏捷過程(三)

編寫的4個測試用例全部通過了,但是如果想對迭代器中每一個元素的計算結(jié)果進(jìn)行驗證現(xiàn)有的函數(shù)就無法完成要求了。
下面運用重構(gòu)中的抽取函數(shù)分解Customer類中超長的方法statement(),這個函數(shù)完成的功能有些無所不包了。既計算各個租借的費用和常客積點,又要計算客戶需要交納的費用總和,最后還要輸出報表的表頭和表尾。另外,現(xiàn)有的快速設(shè)計對變化的應(yīng)對不足,客戶的電影分類可能會出現(xiàn)變化,如果去掉兒童片加上科幻片、故事片怎么辦,客戶的收費規(guī)則發(fā)生變化了怎么辦。根據(jù)前面所說,他的味道不是一般的臭。
第一步:抽取函數(shù)
我們先把statement計算各個租借的費用的職責(zé)分離到一個單獨的函數(shù)中。
private double amountFor(Rental rental){
????????????? double thisAmount=0.0;
????????????? switch (rental.getMovie().getPriceCode()) {
????????????? case Movie.REGULAR:
???????????????????? thisAmount+=2;
???????????????????? if(rental.getDayRented()>2)
??????????????????????????? thisAmount+=(rental.getDayRented()-2)*1.5;
???????????????????? break;
????????????? case Movie.CHILDRENS:
???????????????????? thisAmount+=1.5;
???????????????????? if(rental.getDayRented()>3)
??????????????????????????? thisAmount+=(rental.getDayRented()-3)*1.5;
???????????????????? break;
????????????? case Movie.NEW_RELEASE:
???????????????????? thisAmount+=(rental.getDayRented())*3;
???????????????????? break;
????????????? }
????????????? return thisAmount;
?????????????
?????? }
把原來的計算各個租借費用的部分注釋起來,把private double thisAmount=0.0; 一句改為double thisAmount=amountFor(each);再次運行測試用例,和第一次的結(jié)果對比
我們通過人工比對輸出結(jié)果,輸出結(jié)果相同。我們稍后會通過測試用例由套件自動比對。
如果這一步我們的測試fail掉了,由于我們只走了很小的一步,因此我們可以輕易的退回去。記住,我們始終保持測試-〉編碼(重構(gòu))-〉測試的步驟,小步快走的穩(wěn)定節(jié)奏。
測試全部通過后,我們可以果斷的刪除剛才留在statement函數(shù)中我們注釋過的臨時代碼。
分析我們剛剛抽取出來的amountFor函數(shù),它只使用了rental類中的成員變量,放在Customer
類中并不合適,因此我們繼續(xù)重構(gòu),把amountfor函數(shù)移動到Rental類中。
這里我們使用了集成開發(fā)環(huán)境中的功能:
這里我們看到eclipse自動偵測出目標(biāo)的類為rental,我們把新的函數(shù)改名為getcharge,并勾選在原類型中創(chuàng)建委托,可以點擊預(yù)覽按鈕察看重構(gòu)結(jié)果,最后的結(jié)果如下:
Rental 類中:
double getCharge(){
????????????? double thisAmount=0.0;
????????????? switch (getMovie().getPriceCode()) {
????????????? case Movie.REGULAR:
???????????????????? thisAmount+=2;
???????????????????? if(getDayRented()>2)
??????????????????????????? thisAmount+=(getDayRented()-2)*1.5;
???????????????????? break;
????????????? case Movie.CHILDRENS:
???????????????????? thisAmount+=1.5;
???????????????????? if(getDayRented()>3)
??????????????????????????? thisAmount+=(getDayRented()-3)*1.5;
???????????????????? break;
????????????? case Movie.NEW_RELEASE:
???????????????????? thisAmount+=(getDayRented())*3;
???????????????????? break;
????????????? }
????????????? return thisAmount;
?????????????
?????? }
可以看到比amountfor函數(shù)更加簡化。
Customer類中:
private double amountFor(Rental rental){
????????????? return rental.getCharge();
?????? }
保留了一個rental示例的委托調(diào)用。
再次運行測試用例,通過。
我們繼續(xù)前進(jìn)!
我們回到Customer類中,察看Statement函數(shù)中的thisAmount變量,我們發(fā)現(xiàn)他的結(jié)果并沒有發(fā)生變化,我們可以通過重構(gòu)把這個無用的臨時變量除去。直接把thisamount=amountFor(each);的語句右側(cè)考到totalAmount+=thisAmount;語句右側(cè),編譯器會提示thisamount變量并未使用,直接雙擊quick fix 除去這個變量。再次運行測試用例,通過。
下一步我們把計算常客積點的職責(zé)也從statement函數(shù)中分離出來:
我們添加函數(shù)
private int getFrequentCount(Rental rental){
?????????????
????????????? if (rental.getMovie().getPriceCode()==Movie.NEW_RELEASE&&rental.getDayRented()>1)
???????????????????? return 2;
????????????? else return 1;
?????? }
再把計算常客積點的部分改寫如下:
???????????????????? frequentCount+=getFrequentCount(each);
測試后我們發(fā)現(xiàn)常客積點的計算和類Rental的關(guān)系更密切,我們再次移動getFrequentCount到rental類中。測試通過后,計算常客積點的部分改寫如下:
???????????????????? frequentCount+= each.getFrequentCount();
接下來,我們把statement最后的兩個臨時變量frequentCount、totalAmount也通過替換為函數(shù)查詢消除掉。
添加函數(shù)
private double getTotalCharge(){
????????????? double result=0.0;
????????????? Enumeration rental=rentals.elements();
????????????? while (rental.hasMoreElements()) {
???????????????????? Rental rent = (Rental) rental.nextElement();
???????????????????? result+=rent.getCharge();
????????????? }
????????????? return result;
?????? }
把臨時變量totalAmount替換為getTotalCharge()
添加函數(shù)
private int getTotalFrequentCount(){
????????????? int result=0;
????????????? Enumeration rental=rentals.elements();
????????????? while (rental.hasMoreElements()) {
???????????????????? Rental each = (Rental) rental.nextElement();
???????????????????? result+=each.getFrequentCount();
????????????? }
????????????? return result;
?????? }
把臨時變量frequentCount替換為getTotalFrequentCount
相應(yīng)的,我們在測試中添加以下四條測試用例:
public void testGetCharge(){
????????????? Enumeration rentals=tom.getRentals().elements();
????????????? while (rentals.hasMoreElements()) {
???????????????????? Rental each = (Rental) rentals.nextElement();
???????????????????? switch(each.getMovie().getPriceCode()){
???????????????????? case Movie.CHILDRENS:
??????????????????????????? assertEquals(1.5,each.getCharge(),.1);
???????????????????????????
??????????????????????????? break;
???????????????????? case Movie.NEW_RELEASE:
??????????????????????????? assertEquals(15,each.getCharge(),.1);
??????????????????????????? break;
???????????????????? case Movie.REGULAR:
??????????????????????????? assertEquals(6.5,each.getCharge(),.1);
??????????????????????????? break;
???????????????????? }
?????? }
?????? }
????????????? public void testgetFrequentCount(){
???????????????????? Enumeration rentals=tom.getRentals().elements();
???????????????????? while (rentals.hasMoreElements()) {
??????????????????????????? Rental each = (Rental) rentals.nextElement();
??????????????????????????? switch(each.getMovie().getPriceCode()){
??????????????????????????? case Movie.CHILDRENS:
?????????????????????????????????? assertEquals(1,each.getFrequentCount(),.1);
??????????????????????????????????
?????????????????????????????????? break;
??????????????????????????? case Movie.NEW_RELEASE:
?????????????????????????????????? assertEquals(2,each.getFrequentCount(),.1);
?????????????????????????????????? break;
??????????????????????????? case Movie.REGULAR:
?????????????????????????????????? assertEquals(1,each.getFrequentCount(),.1);
?????????????????????????????????? break;
??????????????????????????? }
????????????? }
?????? }
????????????? public void testGetTotalCharge(){
???????????????????? assertEquals(23,tom.getTotalCharge(),.1);
????????????? }
????????????? public void testGetTotalFrequentCount(){
???????????????????? assertEquals(4,tom.getTotalFrequentCount(),.1);
????????????? }
現(xiàn)在我們就可以對迭代器中的每個元素的結(jié)果進(jìn)行驗證了。