<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ivaneeo's blog

    自由的力量,自由的生活。

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

    #

    現在我運用同樣手法處理getFrequentRenterPoints()。重構前的樣子如下:
    class Movie...
        int getFrequentRenterPoints(int daysRented) {
           if((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
              return 2;
           else
              return 1;
        }

    首先我把這個函數移到Price class里頭:
    class Movie...
        int getFrequentRenterPoints(int daysRented) {
           return _price.getFrequentPoints(daysRented);
        }
    class Price...
        int getFrequentRenterPoints(int daysRented) {
           if((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
              return 2;
           else
              return 1;
        }

    但是這一次我不把superclass函數聲明為abstract。我只是為[新片類型]產生一個覆寫函數(override method),并在superclass內留下一個已定義的函數,使它成為一種缺省行為。

    class NewReleasePrice
        int getFrequentRenterPoints(int daysRented) {
           return (daysRented > 1) ? 2 : 1;
        }

    class Price...
        int getFrequentRenterPoints(int daysRented) {
           return 1;
        }
    posted @ 2005-08-16 15:50 ivaneeo 閱讀(157) | 評論 (0)編輯 收藏

    現在我要對getCharge()實施Move Method(142).下面是重構前的代碼:
    class Movie...
    double getCharge(int daysRented) {
        double result = 0;
        switch(getPriceCode()) {   //取得影片出租價格
              case Movie.REGULAR:   //普通片
                 result+= 2;
                 if(getDaysRented() > 2)
                    result+= (getDaysRented() - 2) * 1.5;
                 break;
              case Movie.NEW_RELEASE:   //新片
                 result+= getDaysRented() * 3;
                 break;
              case Movie.CHILDRENS:   //兒童片
                 result+= 1.5;
                 if(getDaysRented() > 3)
                    result+= (getDaysRented() - 3) * 1.5;
                 break;
           }
        return result;
    }

    搬移動作很簡單。下面是重構后的代碼:
    class Movie...
        double getCharge(int daysRented) {
           return _price.getCharge(daysRented);
        }


    class Price...
       double getCharge(int daysRented) {
        double result = 0;
        switch(getPriceCode()) {   //取得影片出租價格
              case Movie.REGULAR:   //普通片
                 result+= 2;
                 if(getDaysRented() > 2)
                    result+= (getDaysRented() - 2) * 1.5;
                 break;
              case Movie.NEW_RELEASE:   //新片
                 result+= getDaysRented() * 3;
                 break;
              case Movie.CHILDRENS:   //兒童片
                 result+= 1.5;
                 if(getDaysRented() > 3)
                    result+= (getDaysRented() - 3) * 1.5;
                 break;
           }
        return result;
    }

    搬移之后,我就可以開始運用Replace Conditional with Polymorphism(255)了。
    下面是重構前的代碼:
    class Price...
       double getCharge(int daysRented) {
        double result = 0;
        switch(getPriceCode()) {   //取得影片出租價格
              case Movie.REGULAR:   //普通片
                 result+= 2;
                 if(getDaysRented() > 2)
                    result+= (getDaysRented() - 2) * 1.5;
                 break;
              case Movie.NEW_RELEASE:   //新片
                 result+= getDaysRented() * 3;
                 break;
              case Movie.CHILDRENS:   //兒童片
                 result+= 1.5;
                 if(getDaysRented() > 3)
                    result+= (getDaysRented() - 3) * 1.5;
                 break;
           }
        return result;
    }

    我的作法是一次取出一個case分支,在相應的class內建一個覆寫函數(override method)。先從RegularPrice開始:
    class RegularPrice...
        double getCharge(int daysRented) {
           double result = 2;
           if(daysRented > 2)
              result += (daysRented - 2) * 1.5;
           return result;
        }

    class ChildernsPrice...
        double getCharge(int daysRented) {
           double result = 1.5;
           if(daysRented > 3)
              result += (daysRented - 3) * 1.5;
           return result;
        }

    class NewReleasePrice...
    double getCharge(int daysRented) {
           return daysRented * 3;
        }

    處理完所有case分支之后,我就把Price.getCharge()聲明為abstract:
    class Price...
        abstract double getCharge(int daysRented);
    posted @ 2005-08-15 17:21 ivaneeo 閱讀(168) | 評論 (0)編輯 收藏

    首先我要使用Replace Type Code with State/Strategy(227).第一步驟是針對[與型別相依的行為]使用Self Encapsulate Field(171),確保任何時候都通過gettingsetting兩個函數來運用這些行為。由于多數代碼來自其他classes,所以多數函數都已經使用getting函數。但構造函數(constructor)仍然直接訪問價格代碼:
    class Movie...
        public Movie(String name, int priceCode) {
           _title = name;
           _priceCode = priceCode;
        }

    我可以用一個setting函數來代替:
    class Movie...
        public Movie(String name, int priceCode) {
           _title = name;
           setPriceCode(priceCode);
        }
    現在我加入新class,并在price對象中提供[與型別相依的行為]。為了實現這一點,我在Price內加入一個抽象函數(abstract method),并在其所有subclasses中加上對應的具體函數(concrete method):

    abstract class Price {
        abstract int getPriceCode();   //取得價格代號
    }
    class ChildernsPrice extends Price {
        int getPriceCode() {
           return Movie.CHILDERNS;
        }
    }
    class NewReleasePrice extends Price {
        int getPriceCode() {
           return Movie.NEW_RELEASE;
        }
    }
    class RegularPrice extends Price {
        int getPriceCode() {
           return Movie.REGULAR;
        }
    }

    現在,我需要修改Movie class內的[價格代號]訪問函數(get/set函數,如下),讓它們使用新class。下面是重構前的樣子:
    public int getPriceCode() {
        return _priceCode;
    }
    public void setPriceCode(int arg) {
        _priceCode;
    }
    private int _priceCode;

    這個意味我必須在Movie class內保存一個price對象,而不再是保存一個_priceCode變量。此外我還需要修改訪問函數:
    class Movie...
        public int getPriceCode() {   //取得價格代號
           return _price.getPriceCode();
        }
        public void setPriceCode(int arg) {   //設定價格代碼
           switch(arg) {
              case REGULAR:   //普通片
                 _price = new RegularPrice();
                 break;
              case CHILDERNS:   //兒童片
                 _price = new ChildernsPrice();
                 break;
              case NEW_RELEASE:   //新片
                 _price = new NewReleasePrice();
                 break;
              default:
                 throw new IllegalArument Exception("Incorrect Price Code");
           }
        }
        private Price _price;
    posted @ 2005-08-15 17:18 ivaneeo 閱讀(176) | 評論 (0)編輯 收藏

    終于。。。。。我們來到繼承(inheritance)
    我們有數種影片類型,它們以不同的方式回答相同的問題。這聽起來很像subclasses的工作。我們可以建立Movie的三個subclasses,每個都有自己的計費法。

    這么一來我就可以運用多態(polymorphism)來取代switch語句了。很遺憾的是這里有個小問題,不能這么干。一部影片可以在生命期周期內修 改自己的分類,一個對象卻不能在生命周期內修改自己的分類,一個對象卻不能在生命周期內修改自己所屬的class。不過還是有一個解決方法:state pattern(模式)。加入這一層間接性,我們就可以在Price對象內進行subclassing動作,于是便可在任何必要時刻修改價格。

    為了引入state模式,我使用三個重構準則。首先運用Replace Type Code with State/Strategy(227),將[與型相依的行為](type code behavior)搬移至state模式內。然后運用Move Method(142)將switch語句移到Price class里頭。最后運用Replace Conditional with Polymorphism(255)去掉switch語句。
    posted @ 2005-08-15 16:16 ivaneeo 閱讀(173) | 評論 (0)編輯 收藏

    運用多態(polymorphism)取代與價格相關的條件邏輯
    這個問題的第一部分是switch語句。在另一個對象的屬性(attribute)基礎上運用switch語句,并不是什么好注意。如果不得不使用,也應該在對象自己的數據上使用,而不是在別人的數據上使用。
    class Rental...
    double getCharge() {
        double result = 0;
        switch(getMovie().getPriceCode()) {   //取得影片出租價格
              case Movie.REGULAR:   //普通片
                 result+= 2;
                 if(getDaysRented() > 2)
                    result+= (getDaysRented() - 2) * 1.5;
                 break;
              case Movie.NEW_RELEASE:   //新片
                 result+= getDaysRented() * 3;
                 break;
              case Movie.CHILDRENS:   //兒童片
                 result+= 1.5;
                 if(getDaysRented() > 3)
                    result+= (getDaysRented() - 3) * 1.5;
                 break;
           }
        return result;
    }

    這暗示getCharge()應該移到Movie class里頭去:
    class Movie...
    double getCharge(int daysRented) {
        double result = 0;
        switch(getPriceCode()) {   //取得影片出租價格
              case Movie.REGULAR:   //普通片
                 result+= 2;
                 if(getDaysRented() > 2)
                    result+= (getDaysRented() - 2) * 1.5;
                 break;
              case Movie.NEW_RELEASE:   //新片
                 result+= getDaysRented() * 3;
                 break;
              case Movie.CHILDRENS:   //兒童片
                 result+= 1.5;
                 if(getDaysRented() > 3)
                    result+= (getDaysRented() - 3) * 1.5;
                 break;
           }
        return result;
    }

    為了讓它得以運作,我必須把[租期長度]作為參數傳遞進去。當然,[租期長度]來自 Rental對象.計算費用時需要兩份數據:[租期長度]和[影片類型]。為什么我選擇[將租期長度傳給Movie對象]而不是[將影片類型傳給 Rental對象]呢?因為本系統可能發生的變化是加入新影片類型,這種變化帶有不穩定傾向。如果影片類型有所變化,我希望掀起最小的漣漪,所以我選擇在 Movie對象內計算費用。

    我把上述計費方法放進Movie class里頭,然后修改Rental的getCharge(),讓它使用這個新函數:
    class Rental...
        double getCharge() {
           return _movie.getCharge(_daysRented);
        }
    posted @ 2005-08-15 14:54 ivaneeo 閱讀(184) | 評論 (0)編輯 收藏

    很明顯看出來,htmlStatement()和statement()是不同的?,F在,我應該脫下[重構]的帽子,戴上[添加功能]的帽子,戴上[添加功能]的帽子。我可以像下面這樣編寫htmlStatement(),并添加相應測試:

    public String htmlStatement() {
        Enumeration rentals = _rentals.elements();
        String result = "<H1>Rental Record for <EM> " + getName() + "</EM></H1><P>\n";
        while(rentals.hasMoreElements()) {
           Rental each = (Rental)rentals.nextElement();    //取得一筆租借記錄

              result += each.getMovie().getTitle() + ":" +
                 String.valueOf(each.getCharge()) + "<BR>\n";
        }
    //   add footer lines(結尾打印)
        result += "<P>You owe <EM>" + String.valueOf(getTotalCharge()) + "</EM><P> \n";
        result += "On this rental you earned <EM>" + String.valueOf(getTotalfrequentRenterPoints()) +
           "</EM>frequent renter points<P>";
        return result;
    }

    通過計算邏輯的提煉,我可以完成一個htmlStatement(),并復用(reuse)原本statement()內的所有計算。我不必剪剪貼貼,所以如果計算規則發生改變,我只需在程序中做一處修改。
    posted @ 2005-08-15 14:29 ivaneeo 閱讀(164) | 評論 (0)編輯 收藏

    然后以同樣手法處理frequentRenterPoints:
    class Customer...
    public String statement() {
        int frequentRenterPoints = 0;
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for * " + getName() + "\n";
        while(rentals.hasMoreElements()) {
           Rental each = (Rental)rentals.nextElement();    //取得一筆租借記錄

         frequentRenterPoints += each.getFrequentRenterPoints();

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(getTotalCharge()) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    --------------------------------------------------------------------------------------------------------------------

    public String statement() {
        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.getCharge()) + "\n";
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(getTotalCharge()) + " \n";
        result += "You earned " + String.valueOf(getTotalfrequentRenterPoints()) +
           "frequent renter points";
        return result;
    }

    // 譯注:此即所謂query method
    private int getTotalFrequentRenterPoints() {
        int result = 0;
        Enumeration rentals = _rentals.elements();
        while(rentals.hasMoreElements()) {
             Rental each = (Rental)rentals.nextElement();
             result += each.getFrequentRenterPoints();
        }
        return result;
    }
    posted @ 2005-08-15 14:10 ivaneeo 閱讀(172) | 評論 (0)編輯 收藏

    正如我在前面提過的,臨時變量可能是個問題。它們只在自己所屬的函數中有效,所以它們會助長[冗長而復雜]的函數。這里我們有兩個臨時變量,兩者都是用來 從Customer對象相關的Rental對象中獲得某個總量。不論ASCII版或HTML版都需要這些總量。我打算運用Replace Temp with Query(120),并利用所謂的query method來取代totalAmount或frequentRentalPoints這兩個臨時變量。由于class內的任何函數都可以取用(調用)上述所謂query methods,所以它可能夠促進較干凈的設計,而非冗長復雜的函數:

    class Customer...
    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();    //取得一筆租借記錄

         frequentRenterPointers += each.getFrequentRenterPoints();

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
              totalAmount += each.getCharge();
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(totalAmount) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    首先我以Customer class的getTotalCharge()取代totalAmount:
    class Customer...
    public String statement() {
        int frequentRenterPoints = 0;
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for * " + getName() + "\n";
        while(rentals.hasMoreElements()) {
           Rental each = (Rental)rentals.nextElement();    //取得一筆租借記錄

         frequentRenterPointers += each.getFrequentRenterPoints();

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(getTotalCharge()) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    //  譯注:次即query method
    private double getTotalCharge() {
        double result = 0;
        Enumeration rentals = _rentals.elements();
        while(rentals.hasMoreElements()) {
           Rental each = (Rental)rentals.nextElement();
           result += each.getCharge();
        }
        return result;
    }
    這并不是Replace Temp with Query(120)的最簡單情況。由于totalAmount在循環內部被賦值,我不得不把循環復制到query method中。
    posted @ 2005-08-15 13:55 ivaneeo 閱讀(223) | 評論 (0)編輯 收藏

    提取[常客積點計算]代碼
    首先我們需要針對[常客積點計算]這部分代碼(以下粗體部分)運用Extract Method(110)重構準則:
    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();    //取得一筆租借記錄

           //   add frequent renter points(累加??头e點)
              frequentRenterPoints ++;
              if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&
                 each.getDaysRented() > 1)
                 frequentRenterPoints ++;

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
              totalAmount += each.getCharge();
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(totalAmount) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    再一次我又要尋找局部變量。這里再一次用到了each,而它可以被當作參數傳入新函數中。另一個臨時變量是frequentRenterPoints。本 例中的它在被使用之前已經先有初值,但提煉出來的函數并沒有讀取改值,所以我們不需要將它當作參數傳進去,只需對它執行[付添賦值操作](appending assignment,operator+=)就行了。

    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();    //取得一筆租借記錄

         frequentRenterPointers += each.getFrequentRenterPoints();

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
              totalAmount += each.getCharge();
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(totalAmount) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    class Rental...
        int getFrequentRenterPoints() {
           if((getMovie().getPriceCode() == Movie.NEW_RELEASE)
              && getDaysRented() > 1)
              return 2;
           else
              return 1;
        }
    posted @ 2005-08-15 13:29 ivaneeo 閱讀(272) | 評論 (0)編輯 收藏

    Customer.statement():
    public String statement() {
        double totalAmount = 0;
        int frequentRenterPoints = 0;
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for * " + getName() + "\n";
        while(rentals.hasMoreElements()) {
           double thisAmount = 0;
           Rental each = (Rental)rentals.nextElement();    //取得一筆租借記錄

           thisAmount = each.getCharge();

           //   add frequent renter points(累加常客積點)
              frequentRenterPoints ++;
              if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&
                 each.getDaysRented() > 1)
                 frequentRenterPoints ++;

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(thisAmount) + "\n";
              totalAmount += thisAmount;
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(totalAmount) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }

    下一件引我注意的事時:thisAmount如今變成多余了.它接受each.getCharge()的執行結果,然后就不再有任何改變.所以我可以運用Replace Temp with Query(120)把thisAmount除去:
    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();    //取得一筆租借記錄

           //   add frequent renter points(累加常客積點)
              frequentRenterPoints ++;
              if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&
                 each.getDaysRented() > 1)
                 frequentRenterPoints ++;

              result += "\t" + each.getMovie().getTitle() + "\t" +
                 String.valueOf(each.getCharge()) + "\n";
              totalAmount += each.getCharge();
        }
    //   add footer lines(結尾打印)
        result += "Amount owed is " + String.valueOf(totalAmount) + " \n";
        result += "You earned " + String.valueOf(frequentRenterPoints) +
           "frequent renter points";
        return result;
    }
    我喜歡盡量除去這一類臨時變量.臨時變量往往形成問題.它們會導致大量參數被傳來傳 去,而其實完全沒有這種必要.你很容易失去它們的蹤跡,尤其在長長的函數之中更是如此.當然我這么做也需付出性能上的代價,例如本例的費用就被計算了兩 次.但是這很容易在Rental class中被優化.而且如果代碼有合理的組織和管理,優化會有很好的效果.
    posted @ 2005-08-15 13:12 ivaneeo 閱讀(190) | 評論 (0)編輯 收藏

    僅列出標題
    共67頁: First 上一頁 53 54 55 56 57 58 59 60 61 下一頁 Last 
    主站蜘蛛池模板: 男人j进入女人j内部免费网站| h视频在线免费看| 亚洲av无码一区二区三区乱子伦 | 在线精品亚洲一区二区小说 | 在线免费不卡视频| 九九全国免费视频| 亚洲麻豆精品果冻传媒| 青青青国产免费一夜七次郎| 成年免费a级毛片免费看无码 | 成人性生交大片免费看好| 亚洲中文字幕日本无线码| 国产aⅴ无码专区亚洲av麻豆| 久久久久国产精品免费免费搜索| 一出一进一爽一粗一大视频免费的| 亚洲视频在线观看网址| 亚洲美女高清一区二区三区| 亚洲精品成人在线| 亚洲电影免费观看| 国产精品永久免费| 亚洲国产精品网站在线播放| 久久久久亚洲精品无码蜜桃| 亚洲福利中文字幕在线网址| 亚洲AV无码精品国产成人| 美女黄网站人色视频免费国产| 久久久久久免费一区二区三区 | 一本色道久久综合亚洲精品蜜桃冫 | 中国一级特黄的片子免费 | 亚洲精品免费在线观看| 亚洲国产av一区二区三区| 亚洲天堂免费在线| 久久伊人免费视频| 久久WWW免费人成—看片| 亚洲国产日韩a在线播放| 亚洲手机中文字幕| 亚洲AV无码精品色午夜在线观看| 亚洲av无码天堂一区二区三区 | 99re热免费精品视频观看| 国产成人久久AV免费| 国产精品免费久久久久久久久 | 成人黄动漫画免费网站视频| 99热这里只有精品6免费|