<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

    #

    范例(Examples)
    下面是Account class的部分代碼:
    class Account...
        private AccountType _type;
        private double _interestRate;
        double interestForAmount_days(double amount, int days) {
           return _interestRate * amount * days / 365;
        }
    我想把表示利率的_interestRate搬移到AccountType class去。目前已有數個函數引用了它,interestForAmount_days()就是其一。下一步我要在AccountType中建立_interestRate field以及相應的訪問函數:
    class AccountType...
        private double _interestRate;

        void setInterestRate(double arg) {
           _interestRate = arg;
        }
        double getInterestRate() {
           return _interestRate;
        }

    這時候我可以編譯新的 AccountType class。
    現在,我需要讓Account class中訪問_interestRate field的函數轉而使用AccountType對象,然后刪除Account class中的_interestRate field。我必須刪除source field,才能保證其訪問函數的確改變了操作對象,因為編譯器會幫我指出未正確獲得修改的函數。
        private double _interestRate;
        double interestForAmount_days(double amount, int days) {
           return _type.getInterestRate() * amount * days / 365;
        }
    posted @ 2005-08-30 14:46 ivaneeo 閱讀(190) | 評論 (0)編輯 收藏

    作法(Mechanics)
      • 如果field的屬性是public,首先使用Encapsulate Field(206)將它封裝起來。
          • ==》如果你有可能移動那些頻繁訪問該field的函數,或如果有許多函數訪問某個field,先使用Self Encapsulate Field(171)也許會有幫助。
      • 編譯,測試。
      • 在target class中建立與source field相同的field,并同時建立相應的設值/取值(setting/getting)函數。
      • 編譯target class。
      • 決定如何在source object中引用target object。
          • ==》一個現成的field或method可以助你得到target object。如果沒有,就看能否輕易建立這樣一個函數。如果還不行,就得在source class中新建一個field來存放target object。這可能是個永久性修改,但你也可以暫不公開它,因為后續重構可能會把這個新建field除掉。
      • 刪除source field。
      • 將所有[對source field的引用]替換為[對target適當函數的調用]。
          • ==》如果是[讀取]該變量,就把[對source field的引用]替換為[對target取值函數(getter)的調用];如果是[賦值]該變量,就把[對source field的引用]替換成[對設值函數(setter)的調用]。
          • ==》如果source field不是private,就必須在source class的所有subclasses中查找source field的引用點,并進行相應替換。
      • 編譯,測試。
    posted @ 2005-08-30 14:31 ivaneeo 閱讀(155) | 評論 (0)編輯 收藏

    動機(Motivation)
    如果我發現,對于一個field(值域),在其所駐class之外的另一個class中有更多函數使用了它,我就會考慮搬移這個field。上述所謂[使 用]可能通過設值/取值(setting/getting)函數間接進行。我也可能移動該field的用戶(某函數),這取決于是否需要保持接口不受變 化。如果這些函數看上去很合適待在原地,我就選擇搬移field。

    使用Extract Class(149)時,我也可能需要搬移field。此時我會先搬移field,然后再搬移函數。
    posted @ 2005-08-30 14:15 ivaneeo 閱讀(146) | 評論 (0)編輯 收藏

    你的程序中,某個field(值域)被其所駐class之外的另一個class更多地用到。

    在target class建立一個new field,修改source field的所有用戶,令它們改用new field。

    Move_Field.png
    posted @ 2005-08-30 13:55 ivaneeo 閱讀(163) | 評論 (0)編輯 收藏

    范例(Examples)
    我用一個表示[帳戶]的account class來說明這項重構:
    class Account...
        double overdraftCharge() {   //透支金計費,它和其他class的關系似乎比較密切。
           if(_type.isPremium()) {
              double result = 10;
              if(_daysOverdrawn > 7)
                 result += (_daysOverdrawn -7) * 0.85;
              return result;
           }
           else return _daysOverdrawn * 1.75;
        }
        double bankCharge() {
           double result = 4.5;
           if(_daysOverdrawn > 0) result += overdraftCh你arge();
           return result;
        }
        private AccountType _type;
        private int _daysOverdrawn;

    假設有數種新帳戶,每一種都有自己的[透支金計費規則]。所以我希望將overdraftCharge()搬移到AccountType class去。

    第一步要做的是:觀察被overdraftCharge()使用的每一特性(features),考慮是否值得將它們與overdraftCharge()一起移動。此例之中我需要讓_daysOverdrawn值域留在Account class,因為其值會隨不同種類的帳戶而變化。然后,我將overdraftCharge()函數碼拷貝到AccountType中,并做相應調整。
    class AccountType...
        double overdraftCharge(int daysOverdrawn) {
           if(isPremium()) {
              double result = 10;
              if(daysOverdrawn >7)
                 result += (daysOverdrawn - 7) * 0.85;
              return result;
            }
           else return daysOverdrawn * 1.75;
        }
    在這個例子中,[調整]的意思是:(1)對于[使用AccountType特性]的語句,去掉──type;(2)想辦法得到依舊需要的Account class特性。當我需要使用source class特性,我有四種選擇:(1)將這個特性也移到target class;(2)建立或使用一個從target class到source的引用(指涉)關系;(3)將source object當作參數傳給target method;(4)如果所需特性是個變量,將它當作參數傳給target method。

    本例中我將_daysOverdrawn變量作為參數傳給target method(上述(4))。

    調整target method使之通過編譯,而后我就可以將source method的函數本體替換為一個簡單的委托動作(delegation),然后編譯并測試:
        class Account...
           double overdraftCharge() {
              return _type.overdraftCharge(_daysOverdrawn);
           }
    我可以保留代碼如今的樣子,也可以刪除source method。如果決定刪除,就得找出source method的所有調用者,并將這些調用重新定向,改調用Account的bankCharge():
    bankCharge():
        class Account...
           double bankCharge() {
              double result = 4.5;
              if(_daysOverdrawn > 0)
                 result += _type.overdraftCharge(_daysOverdrawn);
              return result;
            }
    所有調用點都修改完畢后,我就可以刪除source method在Account中的聲明了。我可以在每次刪除之后編譯并測試,也可以一次性批量完成。如果被搬移的函數不是private,我還需要檢查其 他classes是否使用了這個函數。在強型(strongly typed)語言中,刪除source method聲明式后,編譯器幫我發現任何遺漏。

    此例之中被移函數只取用(指涉)一個值域,所以我只需將這個值域作為參數傳給target method就行了。如果被移函數調用了Account中的另一個函數,我就不能這么簡單地處理。這種情況下我必須將source object傳遞給target method:
    class AccountType...
        double overdraftCharge(Account account) {
           if(isPremium()) {
              double result = 10;
              if(account.getDaysOverdrawn() >7)
                 result += (account.getdaysOverdrawn() - 7) * 0.85;
              return result;
            }
           else return daysOverdrawn * 1.75;
        }
    如果我需要source class的多個特性,那么我也會將source object傳遞給target method。不過如果target method需要太多source class特性,就得進一步重構。通常這種情況下我會分解target method,并將其中一部分移回source class。
    posted @ 2005-08-30 11:08 ivaneeo 閱讀(223) | 評論 (0)編輯 收藏

    作法(Mechanics)
      • 檢查source class定義之source method所使用的一切特性(features),考慮它們是否也該被搬移。
          • ==》如果某個特性只被你打算搬移的那個函數用到,你應該將它一并搬移。如果另有其他函數使用了這個特性,你可以考慮將使用該特性的所有函數全部一并搬移。有時侯搬移一組函數比逐一搬移簡單些。
      • 檢查source class的subclass和superclass,看看是否有該函數的其他聲明。
          • ==》如果出現其他聲明,你或許無法進行搬移,除非target class也同樣表現出多態性(polymorphism)。
      • 在target class中聲明這個函數。
          • ==》你可以為此函數選擇一個新名稱 -- 對target class更有意義的名稱。
      • 將source method的代碼拷貝到target method中。調整后者,使其能在新家中正常運行。
          • ==》如果target method使用了source特性,你得決定如何從target method引用source object。如果target class中沒有相應的引用機制,就把source object reference當作參數,轉給新建立的target method。
          • ==》如果source method包含異常處理式(exception handler),你得判斷邏輯上應該由哪個class來處理這一異常。如果應該由source class來負責,就把異常處理式留在原地。
      • 編譯target class。
      • 決定如何從source正確引用target object。
          • ==》可能會有一個現成的值域或函數幫助你取得target object。如果沒有,就看能否輕松建立一個這樣的函數。如果還是不行,你得在source class中新建一個新值域來保存target object。這可能是一個永久性修改,但你也可以讓它保持暫時的地位,因為后繼的其他重構項目可能會把這個新建值域去掉。
      • 修改source method,使之成為一個delegating method(純委托函數)。
      • 編譯,測試。
      • 決定[刪除source method]或將它當作一個delegating method保留下來。
          • ==》如果你經常要在source object中引用target method,那么將source method作為delegating method保留下來會比較簡單。
      • 如果你移除source method,請將source class中對source method的所有引用動作,替換為[對target method的引用動作]。
          • ==》你可以每修改一個引用點就編譯并測試一次。也可以通過一次[查找/替換]改掉所有引用點,這通常簡單一些。
      • 編譯,測試。
    posted @ 2005-08-30 10:51 ivaneeo 閱讀(161) | 評論 (0)編輯 收藏

    動機(Motivation)
    [函數搬移]是重構理論的支柱。如果一個class有太多行為,或如果一個class與另一個class有太多合作而形成高度耦合(highly coupled),我就會搬移函數。通過這種手段,我可以使系統中的classes更簡單,這些classes最終也將更干凈利落地實現系統交付的任務。

    常常我會瀏覽class的所有函數,從中尋找這樣的函數:使用另一個對象的次數比使用自己所駐對象的次數還多。一旦我移動了一些值域,就該做這樣的檢查。 一旦發現[有可能被我搬移]的函數,我就會觀察調用它的那一端、它調用的那一端,以及繼承體系中它的任何一個重定義函數。然后,我會根據[這個函數與哪個 對象的交流比較多],決定其移動路徑。

    這往往不是一個容易做出的決定。如果不能肯定是否應該移動一個函數,我就會繼續觀察其他函數。移動其他函數往往會讓這項決定變得容易一些。有時候,即使你 移動了其他函數,還是很難對眼下這個函數做出決定。其實這也沒什么大不了的。如果真的很難做出決定,那么或許[移動這個函數與否]并不那么重要。所以,我 會憑本能去做,反正以后總是可以修改的。
    posted @ 2005-08-30 10:15 ivaneeo 閱讀(160) | 評論 (0)編輯 收藏

    你的程序中,有個函數與其所駐class之外的另一個class進行更多交流:調用后者,或被后者調用。

    在該函數最常引用(指涉)的class中建立一個有著類似行為的新函數。將舊函數變成一個單純的委托函數(delegating method),或者將舊函數完全移除。

    Move_Method.png
    posted @ 2005-08-30 09:16 ivaneeo 閱讀(162) | 評論 (0)編輯 收藏

    作法(Mechanics)
      • 準備好你的另一個(替換用)算法,讓它通過編譯。
      • 針對現有測試,執行上述的新算法。如果結果于原本結果相同,重構結束。
      • 如果測試結果不同于原先,在測試和調試過程中,以舊算法為比較參照標準。
            • ==》對于每個test case(測試用例),分別以新舊兩種算法執行,并觀察兩者結果是否相同。這可以幫助你看到哪一個test case出現麻煩,以及出現了怎么的麻煩。
    posted @ 2005-08-29 17:25 ivaneeo 閱讀(226) | 評論 (0)編輯 收藏

    動機(Motivation)
    有時侯你會想要修改原先的算法,讓它去做一件與原先動作略有差異的事。這時候你也可以先把原先的算法替換為一個較易修改的算法,這樣后續的修改會輕松許多。

    使用這項重構手法之前,請先確定自己已經盡可能分解了原先函數。替換一個巨大而復雜的算法是非常困難的,只有先將它分解為較簡單的小型函數,然后你才能很有把握地進行算法替換工作。
    posted @ 2005-08-29 17:20 ivaneeo 閱讀(167) | 評論 (0)編輯 收藏

    僅列出標題
    共67頁: First 上一頁 45 46 47 48 49 50 51 52 53 下一頁 Last 
    主站蜘蛛池模板: 亚洲国产夜色在线观看| 日韩免费精品视频| 亚洲精品天堂无码中文字幕| 亚洲啪啪AV无码片| 国产小视频免费观看| 久久不见久久见免费视频7| 四虎国产精品永免费| 亚洲午夜成人精品无码色欲| 亚洲欧洲日韩不卡| 国产亚洲美日韩AV中文字幕无码成人| 69式国产真人免费视频| 免费在线中文日本| 国产一级a毛一级a看免费人娇 | 久操视频在线免费观看| 人妻18毛片a级毛片免费看| 亚洲精品无码久久久久牙蜜区| 亚洲美女人黄网成人女| 亚洲成Av人片乱码色午夜| 亚洲国产精品无码久久青草| 成人免费视频小说| 99久久免费国产香蕉麻豆 | 亚洲日韩中文字幕日韩在线| 成人黄动漫画免费网站视频| 2015日韩永久免费视频播放 | 成人伊人亚洲人综合网站222| 妞干网免费视频在线观看| 永久免费AV无码国产网站| 日本h在线精品免费观看| 99视频免费播放| 日韩av无码久久精品免费| 久久一本岛在免费线观看2020| 免费萌白酱国产一区二区三区| 久久久精品国产亚洲成人满18免费网站| 色一情一乱一伦一视频免费看| 亚洲AⅤ男人的天堂在线观看| 亚洲精品无AMM毛片| 无码天堂亚洲国产AV| 小说区亚洲自拍另类| 国产亚洲女在线线精品| 美女被暴羞羞免费视频| 一级毛片一级毛片免费毛片|