重構-改善既有代碼的設計(一)--重構,第一個案例

什麼是重構

在不改變代碼外在行爲的前提下,對代碼作出修改以改進程序內部的結構
簡單地說就是在代碼寫好後改進它的設計程序員

誰該閱讀這本書

  1. 專業程序員(可以提升你的代碼質量)
  2. 資深設計師和架構規劃師(理解爲何須要重構,哪裏須要重構)

閱讀技巧

帶着疑問去讀:數據結構

  • 若是你想要知道重構是什麼。第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類下this

去除臨時變量

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;
}

測試重構後的方法

保證重構後的方法可以知足全部的需求code

總結

  • 代碼塊俞小,代碼的功能就俞容易管理,代碼的處理和移動也就俞輕鬆
  • 任何不會被修改的變量均可以被當成參數傳入新的函數,至於會被修改的變量須要慎重。若是隻有一個變量會被修改,能夠把它當作返回值。
  • 絕大多數狀況下,函數應該放在它所使用的數據的所屬對象內
  • 最好不要在另外一個對象的屬性基礎上運用switch語句。若是不得不使用,也應該在對象本身的數據上使用,而不是在別人的數據上使用。
  • 使用繼承來適當組織類關係後,能夠用多態取代switch語句。
相關文章
相關標籤/搜索