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

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