![]() |
![]() |
| double thisAmount = 0; switch(each.getMovie().getPriceCode()){ case Movie.REGULAR: thisAmount += 2; if(each.getDaysRented()>2) thisAmount += (each.getDaysRented()-2)*1.5; break; case Movie.NEW_RELEASE: thisAmount += each.getDaysRented()*3; break; case Movie.CHILDRENS: thisAmount += 1.5; if(each.getDaysRented()>3) thisAmount += (each.getDaysRented()-3)*1.5; break; } |
![]() |
![]() |
| public String statement() { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "\n"; while(rentals.hasMoreElements()){ Rental each = (Rental)rentals.nextElement(); double thisAmount = amountFor(each); frequentRenterPoints ++; if((each.getMovie().getPriceCode())==Movie.NEW_RELEASE &&each.getDaysRented()>1) frequentRenterPoints ++; result += "\t" + each.getMovie().getTitle() + "\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; } /** * @param each * @return */ private double amountFor(Rental each) { double thisAmount = 0; switch(each.getMovie().getPriceCode()){ case Movie.REGULAR: thisAmount += 2; if(each.getDaysRented()>2) thisAmount += (each.getDaysRented()-2)*1.5; break; case Movie.NEW_RELEASE: thisAmount += each.getDaysRented()*3; break; case Movie.CHILDRENS: thisAmount += 1.5; if(each.getDaysRented()>3) thisAmount += (each.getDaysRented()-3)*1.5; break; } return thisAmount; } |
| /** * @param aRental * @return */ private double amountFor(Rental aRental) { double result = 0; switch(aRental.getMovie().getPriceCode()){ case Movie.REGULAR: result += 2; if(aRental.getDaysRented()>2) result += (aRental.getDaysRented()-2)*1.5; break; case Movie.NEW_RELEASE: result += aRental.getDaysRented()*3; break; case Movie.CHILDRENS: result += 1.5; if(aRental.getDaysRented()>3) result += (aRental.getDaysRented()-3)*1.5; break; } return result; } |
1、選中函數amountFor()的定義,在右鍵菜單中選擇"重構/移動(dòng)",顯示參數設置對話(huà)框。把新方法名改成getCharge。按下"確定"按鈕,Customer Class中的amountFor()函數被移動(dòng)到Rental Class中,并更名為:getCharge()。
![]() |
| private double amountFor(Rental aRental) { return aRental.getCharge(); } |
| /** * @param this * @return */ private double getCharge() { …… } |
![]() |
![]() |
| public String statement() { …… double thisAmount = each.getCharge(); …… } |
![]() |
| public String statement() { double totalAmount = 0; // 總消費金額 int frequentRenterPoints = 0; // ??头e點(diǎn) Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "\n"; while(rentals.hasMoreElements()){ Rental each = (Rental)rentals.nextElement(); //取得一筆租借記錄 // add frequent renter points(累加 ??头e點(diǎn)) frequentRenterPoints ++; // add bouns for a two day new release rental if((each.getMovie().getPriceCode())==Movie.NEW_RELEASE && each.getDaysRented()>1) frequentRenterPoints ++; // show figures for this rental(顯示此筆租借數據) result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(each.getCharge()) + "\n"; totalAmount += each.getCharge(); } // add footer lines(結尾打?。?br> result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } |
四、重構第三步:提煉"??头e點(diǎn)計算"代碼
目的:提取"??头e點(diǎn)計算"代碼并放在Rental類(lèi)中,"??头e點(diǎn)計算"代碼如下。
| public String statement() { …… // add frequent renter points frequentRenterPoints ++; // add bouns for a two day new release rental if((each.getMovie().getPriceCode())==Movie.NEW_RELEASE && each.getDaysRented()>1) frequentRenterPoints ++; …… } |
重構后的代碼如下:
| frequentRenterPoints += each.getFrequentRenterPoints(); |
重構方法:
Extract Method
Move Method
Change Method signatrue
Inline Method
方法:
1、 首先,抽取代碼到獨立的函數中。
用"抽取方法"重構代碼,函數名:getFrequentRenterPoints。很遺憾,eclipse的不能生成諸如:frequentRenterPoints += getFrequentRenterPoints(Rental aRental); 的代碼。原因是執行自增操作的局部變量frequentRenterPoints要出現在等式右邊,因此抽取函數getFrequentRenterPoints()一定要把frequentRenterPoints作為參數。手工修改函數和對函數的引用,重構后的代碼如下:
| public String statement() { …… while(rentals.hasMoreElements()){ …… frequentRenterPoints += getFrequentRenterPoints(each); …… } …… } /** * @param each * @return */ private int getFrequentRenterPoints(Rental each) { if((each.getMovie().getPriceCode())==Movie.NEW_RELEASE && each.getDaysRented()>1) return 2; else return 1; } |
2、 把getFrequentRenterPoints()移動(dòng)到Rental類(lèi)中。
3、 對getFrequentRenterPoints()"更改方法特征符"為public。
4、 對Customer的函數getFrequentRenterPoints()執行內聯(lián)操作,重構目標完成。
五、重構第四步:去除臨時(shí)變量(totalAmount和frequentRenterPoints)
目的:去除臨時(shí)變量(totalAmount和frequentRenterPoints)
方法:
1、 分析totalAmount和frequentRenterPoints的定義和引用結構如下:
| // 聲明和定義 double totalAmount = 0; int frequentRenterPoints = 0; …… // 在循環(huán)中修改 while(rentals.hasMoreElements()){ …… frequentRenterPoints += each.getFrequentRenterPoints(); …… totalAmount += each.getCharge(); …… } …… // 在循環(huán)外使用 result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; …… |
上述兩個(gè)變量在循環(huán)體外面定義和使用,在循環(huán)中被修改,運用Replace Temp with Query方法去除這兩個(gè)臨時(shí)變量是一項稍微復雜的重構。很遺憾,eclipse目前不支持這樣的重構。
2、手工修改代碼。
六、重構第五步:運用多態(tài)取代與價(jià)格相關(guān)的條件邏輯
目的:
1、 把Rental類(lèi)中的函數getCharge()移動(dòng)到Movie類(lèi)中。
2、 把Rental類(lèi)中的函數getFrequentRenterPoints()移動(dòng)到Movie類(lèi)中。
重構方法:
Move Method
Inline Method
方法:
1、 選中Rental類(lèi)中的函數getCharge(),右鍵菜單選中"重構/移動(dòng)",eclipse提示找不到接收者,不能移動(dòng)。原因在于這行語(yǔ)句:
| switch(getMovie().getPriceCode()){//取得影片出租價(jià)格 |
| switch(_movie.getPriceCode()){ //取得影片出租價(jià)格 |
| class Movie …… /** * @param this * @return */ public double getCharge(int _daysRented) { double result = 0; switch(getPriceCode()){ //取得影片出租價(jià)格 case Movie.REGULAR: // 普通片 result += 2; if(_daysRented>2) result += (_daysRented-2)*1.5; break; case Movie.NEW_RELEASE: // 新片 result += _daysRented*3; break; case Movie.CHILDRENS: // 兒童片 result += 1.5; if(_daysRented>3) result += (_daysRented-3)*1.5; break; } return result; } class Rental…… /** * @param this * @return */ public double getCharge() { return _movie.getCharge(_daysRented); } |
| class Movie …… /** * @param frequentRenterPoints * @param this * @return */ public int getFrequentRenterPoints(int daysRented) { if((getPriceCode())==Movie.NEW_RELEASE && daysRented>1) return 2; else return 1; } class Rental…… /** * @param frequentRenterPoints * @param this * @return */ public int getFrequentRenterPoints(int daysRented) { if((getPriceCode())==Movie.NEW_RELEASE && daysRented>1) return 2; else return 1; } |
| 名稱(chēng) | 功能 |
| 撤銷(xiāo) | 執行上一次重構的"撤銷(xiāo)"。只要除了重構之外尚未執行任何其它源更改,重構撤銷(xiāo)緩沖區就有效。 |
| 重做 | 執行上一次撤銷(xiāo)重構的"重做"。只要除了重構之外尚未執行任何其它源更改,重構撤銷(xiāo)/重做緩沖區就有效。 |
| 重命名 | 啟動(dòng)"重命名"重構對話(huà)框:重命名所選擇的元素,并更正對元素的所有引用(如果啟用了的話(huà))(還在其它文件中)??捎糜冢悍椒?、字段、局部變量、方法參數、類(lèi)型、編譯單元、包、源文件夾和項目,以及解析為這些元素類(lèi)型中的其中一種的文本選擇部分。 |
| 移動(dòng) | 啟動(dòng)"移動(dòng)"重構對話(huà)框:移動(dòng)所選擇的元素,并更正對元素的所有引用(如果啟用了的話(huà))(還在其它文件中)。適用于:一個(gè)實(shí)例方法(可以將它移至某個(gè)組件)、一個(gè)或多個(gè)靜態(tài)方法、靜態(tài)字段、類(lèi)型、編譯單元、包、源文件夾和項目,以及解析為這些元素類(lèi)型中的其中一種的文本選擇部分。 |
| 更改方法特征符 | 啟動(dòng)"更改方法特征符"重構對話(huà)框。更改參數名稱(chēng)、參數類(lèi)型和參數順序,并更新對相應方法的所有引用。此外,可以除去或添加參數,并且可以更改方法返回類(lèi)型和它的可視性??梢詫⒋酥貥嫅糜诜椒ɑ蚪馕鰹榉椒ǖ奈谋具x擇。 |
| 將匿名類(lèi)轉換為嵌套類(lèi) | 啟動(dòng)"將匿名類(lèi)轉換為嵌套類(lèi)"重構對話(huà)框。幫助您將匿名內部類(lèi)轉換為成員類(lèi)??梢詫⒋酥貥嫅糜谀涿麅炔款?lèi)。 |
| 將嵌套類(lèi)型轉換成頂層 | 啟動(dòng)"將嵌套類(lèi)型轉換為頂層類(lèi)型"重構對話(huà)框。為所選成員類(lèi)型創(chuàng )建新的 Java 編譯單元,并根據需要更新所有引用。對于非靜態(tài)成員類(lèi)型,將添加字段以允許訪(fǎng)問(wèn)先前的外圍實(shí)例??梢詫⒋酥貥嫅糜诔蓡T類(lèi)型或解析為成員類(lèi)型的文本。 |
| 下推 | 啟動(dòng)"下推"重構對話(huà)框。將一組方法和字段從一個(gè)類(lèi)移至它的子類(lèi)??梢詫⒋酥貥嫅糜谠谕粋€(gè)類(lèi)型中聲明的一個(gè)或多個(gè)方法和字段或者字段或方法內的文本選擇。 |
| 上拉 | 啟動(dòng)"上拉"重構型中聲明的一個(gè)或多個(gè)方法、字段和成員類(lèi)型,也可以應用于字段、方法或成員類(lèi)型內的文本選擇。向導。將字段或方法移至其聲明類(lèi)的超類(lèi)或者(對于方法)將方法聲明為超類(lèi)中的抽象類(lèi)??梢詫⒋酥貥嫅糜谠谕粋€(gè)類(lèi) |
| 抽取接口 | 啟動(dòng)"抽取接口"重構對話(huà)框。使用一組方法創(chuàng )建新接口并使選擇的類(lèi)實(shí)現該接口,并盡可能地將對該類(lèi)的引用更改為對新接口的引用(可選)??梢詫⒋酥貥嫅糜陬?lèi)型。 |
| 盡可能使用超類(lèi)型 | 啟動(dòng)"盡可能使用超類(lèi)型"對話(huà)框。將某個(gè)類(lèi)型的出現替換為它的其中一個(gè)超類(lèi)型,在執行此替換之前,需要標識所有有可能進(jìn)行此替換的位置。此重構可用于類(lèi)型。 |
| 內聯(lián) | 啟動(dòng)"內聯(lián)"重構對話(huà)框。內聯(lián)局部變量、方法或常量。此重構可用于方法、靜態(tài)終態(tài)字段和解析為方法、靜態(tài)終態(tài)字段或局部變量的文本選擇。 |
| 抽取方法 | 啟動(dòng)"抽取方法"重構對話(huà)框。創(chuàng )建一個(gè)包含當前所選擇的語(yǔ)句或表達式的新方法,并將選擇替換為對新方法的引用??梢允褂镁庉嫴藛沃械臄U大選擇至以獲取有效的選擇范圍。此功能對于清理冗長(cháng)、雜亂或過(guò)于復雜的方法是很有用的。 |
| 抽取局部變量 | 啟動(dòng)"抽取變量"重構對話(huà)框。創(chuàng )建為當前所選擇的表達式指定的新變量,并將選擇替換為對新變量的引用。此重構可用于解析為局部變量的文本選擇??梢允褂镁庉嫴藛沃械臄U大選擇至以獲取有效的選擇范圍。 |
| 抽取常量 | 啟動(dòng)"抽取常量"重構對話(huà)框。從所選表達式創(chuàng )建靜態(tài)終態(tài)字段并替換字段引用,并且可以選擇重寫(xiě)同一表達式的其它出現位置。此重構可用于靜態(tài)終態(tài)字段和解析為靜態(tài)終態(tài)字段的文本選擇。 |
| 將局部變量轉換為字段 | 啟動(dòng)"將局部變量轉換為字段"重構對話(huà)框。將局部變量轉換為字段。如果該變量是在創(chuàng )建時(shí)初始化的,則此操作將把初始化移至新字段的聲明或類(lèi)的構造函數。此重構可用于解析為局部變量的文本選擇。 |
| 封裝字段 | 啟動(dòng)"自封裝字段"重構對話(huà)框。將對字段的所有引用替換為 getting 和 setting 方法。它適用于所選擇的字段或解析為字段的文本選擇。 |
聯(lián)系客服