<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、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### Introduce Local Extension(引入本地擴展) 你所使用的server class需要一些額外函數,但你無法修改這個class。 建立一個新class,使它包含這些額外函數。讓這個擴展品成為source class的subclass (子類〕或wrapper(外覆類)。 ![](https://box.kancloud.cn/2016-08-15_57b1b56cab71a.gif) **動機(Motivation)** 很遺憾,classes的作者無法預知未來,他們常常沒能為你預先準備一些有用的函數。如果你可以修改源碼,最好的辦法就是直接加入自己需要的函數。但你經常無法修改源碼。如果只需要一兩個函數,你可以使用Introduce Foreign Method。 但如果你需要的額外函數超過兩個,外加函數(foreign methods)就很難控制住它 們了。所以,你需要將這些函數組織在一起,放到一個恰當地方去。要達到這一目 的,標準對象技術subclassing和wrapping是顯而易見的辦法。這種情況下我把 subclass 或wrapper稱為local extention(本地擴展〕。 所謂local extention是一個獨立的class,但也是其extended class的subtype(譯注: 這里的subtype不同于subclass;它和extended class并不一定存在嚴格的繼承關系,只要能夠提供extended class的所有特性即可)。這意味它提供original class的一切特性,同時并額外添加新特性。在任何使用original class的地方,你都可以使用local extention取而代之。 使用local extention(本地擴展)使你得以堅持「函數和數據應該被包裝在形式良好 的單元內」這一原則。如果你一直把本該放在extended class 中的代碼零散放置于其他classes中,最終只會讓其他這些classes變得過分復雜,并使得其中函數難以被復用。 在subclass和wrapper之間做選擇時,我通常首選subclass,因為這樣的工作量比較少。制作subclass的最大障礙在于,它必須在對象創建期(object-createion time)實施。如果我可以接管對象創建過程,那當然沒問題;但如果你想在對象創建之后再使用local extention ;就有問題了。此外,"subclassing"還迫使我必須產生一個subclass對象,這種情況下如果有其他對象引用了舊對象,我們就同時有兩個對象保存了原數據!如果原數據是不可修改的(immutable),那也沒問題,我可以放心進行拷貝;但如果原數據允許被修改,問題就來了,因為這時候鬧了雙包,一個修改動作無法同時改變兩份拷貝。這時候我就必須改用wrapper。但使用wrapper時, 對local extention的修改會波及原物(original),反之亦然。 **作法(Mechanics)** - 建立一個extension class,將它作為原物(原類〉的subclass或wrapper。 - 在extension class 中加入轉型構造函數(converting constructors )。 - 所謂「轉型構造函數」是指接受原物(original)作為參數。如果你釆用subclassing方案,那么轉型構造函數應該調用適當的subclass構造函數;如果你采用wrapper方案,那么轉型構造函數應該將它所獲得之引數(argument)賦值給「用以保存委托關系(delegate)」的那個值域。 - 在extension class中加入新特性。 - 根據需要,將原物(original)替換為擴展物(extension)。 - 將「針對原始類(original class)而定義的所有外加函數(foreign methods)」 搬移到擴展類extension中。 **范例(Examples)** 我將以Java 1.0.1的Date class為例。Java 1.1已經提供了我想要的功能,但是在它到來之前的那段日子,很多時候我需要擴展Java 1.0.1的Date class。 第一件待決事項就是使用subclass或wrapper。subclassing是比較顯而易見的辦法: ~~~ Class mfDate extends Date { public nextDay()... public dayOfYear()... ~~~ wrapper則需要用上委托(delegation): ~~~ class mfDate { private Date _original; ~~~ **范例:是用Subclass(子類)** 首先,我要建立一個新的MfDateSub class來表示「日期」(譯注:"Mf"是作者Martin Fowler的姓名縮寫),并使其成為Date的subclass: ~~~ class MfDateSub extends Date ~~~ 然后,我需要處理Date 和我的extension class之間的不同處。MfDateSub 構造函數需要委托(delegating)給Date構造函數: ~~~ public MfDateSub (String dateString) { super (dateString); }; ~~~ 現在,我需要加入一個轉型構造函數,其參數是一個隸屬原類的對象: ~~~ public MfDateSub (Date arg) { super (arg.getTime()); } ~~~ 現在,我可以在extension class中添加新特性,并使用Move Method 將所有外加函數(foreign methods)搬移到extension class。于是,下面的代碼: ~~~ client class... private static Date nextDay(Date arg) { // foreign method, should be on date return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1); } ~~~ 經過搬移之后,就成了: ~~~ class MfDate... Date nextDay() { return new Date (getYear(),getMonth(), getDate() + 1); } ~~~ **范例:是用wrapper(外覆類)** 首先聲明一個wrapping class: ~~~ class mfDate { private Date _original; } ~~~ 使用wrapping方案時,我對構造函數的設定與先前有所不同。現在的構造函數將只是執行一個單純的委托動作(delegation): ~~~ public MfDateWrap (String dateString) { _original = new Date(dateString); }; ~~~ 而轉型構造函數則只是對其instance變量賦值而己: ~~~ public MfDateWrap (Date arg) { _original = arg; } ~~~ 接下來是一項枯燥乏味的工作:為原始類的所有函數提供委托函數。我只展示兩個函數,其他函數的處理依此類推。 ~~~ public int getYear() { return _original.getYear(); } public boolean equals (MfDateWrap arg) { return (toDate().equals(arg.toDate())); } ~~~ 完成這項工作之后,我就可以后使用Move Method 將日期相關行為搬移到新class中。于是以下代碼: ~~~ client class... private static Date nextDay(Date arg) { // foreign method, should be on date return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1); } ~~~ 經過搬移之后,就變成: ~~~ class MfDate... Date nextDay() { return new Date (getYear(),getMonth(), getDate() + 1); } ~~~ 使用wrappers有一個特殊問題:如何處理「接受原始類之實體為參數」的函數?例如: public boolean after (Date arg) 由于無法改變原始類〔original),所以我只能以一種方式使用上述的after() : ~~~ aWrapper.after(aDate) // can be made to work aWrapper.after(anotherWrapper) // can be made to work aDate.after(aWrapper) // will not work ~~~ 這樣覆寫(overridden)的目的是為了向用戶隱藏wrapper 的存在。這是一個好策略,因為wrapper 的用戶的確不應該關心wrapper 的存在,的確應該可以同樣地對待wrapper(外覆類)和orignal((原始類)。但是我無法完全隱藏此一信息,因為某些系統所提供的函數(例如equals() 會出問題。你可能會認為:你可以在MfDateWrap class 中覆寫equals(),像這樣: ~~~ public boolean equals (Date arg) // causes problems ~~~ 但這樣做是危險的,因為盡管我達到了自己的目的,Java 系統的其他部分都認為equals() 符合交換律:如果a.equals(b)為真,那么b.equals(a)也必為真。違反這一規則將使我遭遇一大堆莫名其妙的錯誤。要避免這樣的尷尬境地,惟一辦法就是修改Date class。但如果我能夠修改Date ,我又何必進行此項重構?所以,在這種情況下,我只能(必須〕向用戶暴露「我進行了包裝」這一事實。我將以一個新函數來進行日期之間的相等性檢查(equality tests): ~~~ public boolean equalsDate (Date arg) ~~~ 我可以重載equalsDate() ,讓一個重載版本接受Date 對象,另一個重載版本接受MfDateWrap 對象。這樣我就不必檢查未知對象的型別了: ~~~ public boolean equalsDate (MfDateWrap arg) ~~~ subclassing方案中就沒有這樣的問題,只要我不覆寫原函數就行了。但如果我覆寫了original class 中的函數,那么尋找函數時,我會被搞得暈頭轉向。一般來說,我不會在extension class 中覆寫0original class 的函數,我只會添加新函數。 譯注:equality(相等性)是一個很基礎的大題目。《Effective Java》 by Joshua Bloch 第3章,以及《Practical Java》by Peter Haggar 第2章,對此均有很深入的討論。這兩本書對于其他的基礎大題目如Serizable,Comparable,Cloneable,hashCode() 也都有深刻討論。
                  <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>

                              哎呀哎呀视频在线观看