<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### Move Method(搬移函數) (譯注:本節大量保留class,method,source,target等字眼) 你的程序中,有個函數與其所駐class之外的另一個class進行更多交流:調用后者,或被后者調用。 在該函數最常引用(指涉)的class中建立一個有著類似行為的新函數。將舊函數變成一個單純的委托函數(delegating method),或是將舊函數完全移除。 ![](https://box.kancloud.cn/2016-08-15_57b1b56be692d.gif) **動機(Motivation)** 「函數搬移」是重構理論的支柱。如果一個class有太多行為,或如果一個class與另一個class有太多合作而形成高度耦合(highly coupled),我就會搬移函數。通過這種手段,我可以使系統中的classes更簡單,這些classes最終也將更干凈利落地實現系統交付的任務。 常常我會瀏覽class的所有函數,從中尋找這樣的函數:使用另一個對象的次數比使用自己所駐對象的次數還多。一旦我移動了一些值域,就該做這樣的檢查。一旦發現「有可能被我搬移」的函數,我就會觀察調用它的那一端、它調用的那一端,以及繼承體系中它的任何一個重定義函數。然后,我會根據「這個函數與哪個對象的交流比較多」,決定其移動路徑。 這往往不是一個容易做出的決定。如果不能肯定是否應該移動一個函數,我就會繼續觀察其他函數。移動其他函數往往會讓這項決定變得容易一些。有時候,即使你移動了其他函數,還是很難對眼下這個函數做出決定。其實這也沒什么大不了的。 如果真的很難做出決定,那么或許「移動這個函數與否」并不那么重要。所以,我會憑本能去做,反正以后總是可以修改的。 **作法(Mechanics)** - 檢查source class定義之source method所使用的一切特性(features),考慮它們是否也該被搬移。(譯注:此處所謂特性泛指class定義的所有東西,包括值域和函數。) - 如果某個特性只被你打算搬移的那個函數用到,你應該將它一并搬移。如果另有其他函數使用了這個特性,你可以考慮將使用該特性的所有函數全都一并搬移。有時候搬移一組函數比逐一搬移簡單些。 - 檢查source class的subclass和superclass,看看是否有該函數的其他聲明。 - 如果出現其他聲明,你或許無法進行搬移,除非target class也同樣表現出多態性(polylmorphism〕。 - 在target class中聲明這個函數。 - 你可以為此函數選擇一個新名稱——對target class更有意義的名稱。 - 將source method的代碼拷貝到target method中。調整后者,使其能在新家中正常運行。 - 如果target method使用了source特性,你得決定如何從target method引用source object。如果target class中沒有相應的引用機制,就把source object reference當作參數,傳給新建立的target class。 - 如果source method包含異常處理式(exception handler),你得判斷邏輯上應該由哪個來處理這一異常。如果應該由source class負責,就把異常處理式留在原地。 - 編譯target class。 - 決定如何從source正確引用target object。 - 可能會有一個現成的值域或函數幫助你取得target class。如果沒有,就看能否輕松建立一個這樣的函數。如果還是不行,你得在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的引用動作」。 - 編譯,測試。 **范例(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 += overdraftCharge(); 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 class;(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(): ~~~ 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 account.getDaysOverdrawn() * 1.75; } ~~~ 如果我需要source class的多個特性,那么我也會將source object傳遞給target method。不過如果target method需要太多source class特性,就得進一步重構。通常這種情況下我會分解target method,并將其中一部分移回source class。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看