重構-改善既有程式碼的設計(一)--重構第一個案例
阿新 • • 發佈:2019-01-25
什麼是重構
在不改變程式碼外在行為的前提下,對程式碼做出修改以改程序序內部的結構
簡單地說就是在程式碼寫好後改進它的設計
誰該閱讀這本書
- 專業程式設計師(能夠提高你的程式碼質量)
- 資深設計師和架構規劃師(理解為什麼需要重構,哪裡需要重構)
閱讀技巧
帶著疑問去讀:
- 如果你想要知道重構是什麼。第1章夠了
- 如果你想要知道為什麼要重構,第1,2章
- 如果你想知道該在什麼地方重構,第3章
- 如果你想進行重構,第1,2,3,4章。並根據目錄選讀
第1章 重構,第一個案例
public String statement(){ double totalAmount=0; int frequentRenterPoints=0; Enumeration<Rental> rentals = _rentals.elements(); String result = "Rental Record for "+getName()+"\n"; while(rentals.hasMoreElements()){ double thisAmount=0; Rental each = (Rental)rentals.nextElement(); switch (each.getMovie().getPriceCode()) { case Movie.CHILDRENS: thisAmount += 1.5; if(each.getDaysRented()>3){ thisAmount += (each.getDaysRented()-3)*1.5; } break; case Movie.NEW_RELEASE: thisAmount += each.getDaysRented()*3; break; case Movie.REGULAR: thisAmount += 2; if(each.getDaysRented()>2){ thisAmount += (each.getDaysRented()-2)*1.5; } break; default: break; } 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; }
這是隻是一個方法。直接評價:太複雜,複用率低
解決方法
分解並重組
將程式碼按照功能拆分。每個功能只做一件事。
拆除switch並封裝為方法
private double amountFor(Rental each, double result) { switch (each.getMovie().getPriceCode()) { case Movie.CHILDRENS: result += 1.5; if(each.getDaysRented()>3){ result += (each.getDaysRented()-3)*1.5; } break; case Movie.NEW_RELEASE: result += each.getDaysRented()*3; break; case Movie.REGULAR: result += 2; if(each.getDaysRented()>2){ result += (each.getDaysRented()-2)*1.5; } break; default: break; } return result; }
重設變數名
變數名必須保證簡單清楚,不產生歧義。比如上方程式碼的each就是可修改的變數名。因為each到底指的是什麼
搬移程式碼
因為這個方法只使用了rental的資訊。所以需要放在rental類下
去除臨時變數
statement方法中有兩個臨時變數totalAmount和frequentRenterPoints。 做成getTotalAmount和getFrequentRenterPoints方法
public String statement() { double totalAmount = 0; int frequentRenterPoints = 0; // Enumeration介面定義了從一個數據結構得到連續資料的手段 Enumeration rentals = _rentals.elements(); String result = "Rental Record for" + getName() + "\n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(each.getMovie().getPrice().getCharge(each.getDayRented())) + "\n"; } result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n"; result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + "frequent renter points"; return result; } private int getTotalFrequentRenterPoints(){ int result=0; Enumeration rentals=_rentals.elements(); while(rentals.hasMoreElements()){ Rental each=(Rental)rentals.nextElement(); result+=each.getMovie().getFrequentRenterPoints(each.getDayRented()); } return result; } private double getTotalCharge(){ double result =0; Enumeration rentals=_rentals.elements(); while(rentals.hasMoreElements()){ Rental each=(Rental)rentals.nextElement(); result+=each.getMovie().getPrice().getCharge(each.getDayRented()); } return result; }
測試重構後的方法
保證重構後的方法能夠滿足所有的需求
總結
- 程式碼塊俞小,程式碼的功能就俞容易管理,程式碼的處理和移動也就俞輕鬆
- 任何不會被修改的變數都可以被當成引數傳入新的函式,至於會被修改的變數需要慎重。如果只有一個變數會被修改,可以把它當做返回值。
- 絕大多數情況下,函式應該放在它所使用的資料的所屬物件內
- 最好不要在另一個物件的屬性基礎上運用switch語句。如果不得不使用,也應該在物件自己的資料上使用,而不是在別人的資料上使用。
- 使用繼承來適當組織類關係後,可以用多型取代switch語句。