《重構》第七章--讀書筆記

第七章 在對象之間搬移特性
——讀書筆記
在對象的設計過程中,要決定把對象放在哪裏,可能不會一開始就做對,但是可以運用重構,改變自己原先的設計,這就用到了本章所提到額重構手法。
7.1 Move Method(搬移函數)。
問題:你的程序中,有個函數與其所駐類之外的另一個類進行更多交流:調用後者或者被後者調用。
方法:在該函數最常引用的類中建立一個有着類似行爲的新函數,將舊函數編程一個單純的委託函數,或是將舊函數完全移除。
動機:一個類有太多行爲,或者與另一個類有太多合作形成高度耦合,爲了讓系統中的類更簡單,乾淨利落地實現系統交付的任務。
做法:1.檢查源類中被函數所使用的一切特性(包括字段和函數),考慮其是否應該被搬移;2.檢查源類的子類和超類,看看是否有該函數的其他聲明;3.在目標類中聲明該函數;4.將原函數的代碼複製到目標函數中,調整後者,使其能在新家中正常運行;5.編譯目標類;6.決定如何從源函數正確引用目標對象;7.修改源函數,使之成爲一個純委託函數;8.編譯測試;9.決定是否刪除源函數,或將它當作一個委託函數保留下來;如果要移除源函數,將源類中對源函數的所有調用,替換爲對目標函數的調用;10.編譯測試。
7.2 Move Field(搬移字段)。
問題:在你的程序中,某個字段被其所駐類之外的另一個類更多地用到。
方法:在目標類新建一個字段,修改源字段的所有用戶,令它們改用新字段。
動機:對於一個字段,在其所駐類之外的另一個類中有更多的函數使用了它。
做法:1.如果字段的訪問級是public,使用Encapsulate Field將它封裝起來;2.編譯測試;3.在目標類中建立與源字段相同的字段,並同時建立相應的設值/取值函數;4.編譯目標類;5.決定如何在源對象中引用目標對象;6.刪除源字段;7.將所有對源字段的引用替換爲對某個目標函數的調用;8.編譯測試。
7.3 Extract Class(提煉類)。
問題:某個類做了應該由兩個類做的事情。
方法:建立一個新類,將相關的字段和函數從舊類搬移到新類。
動機:一個類應該是一個清楚的抽象,處理一些明確的責任,實際工作中,類可能不斷擴大,加入很多新功能,這樣的類往往有大量函數和數據,這樣的類往往不易理解,所以需要提煉類,將其中獨立的功能提煉出來形成新的類。
做法:1.決定如何分解類所負的責任;2.建立一個新的類,用以表現從舊類中分離出來的責任;3.建立“從舊類訪問新類”的連接關係;4.對於你想搬移的每一個字段,運用Move Field搬移之;5.每次搬移後編譯測試;6.使用Move Method將必要的函數搬移到新類;7.先搬移較低層函數(被其他函數調用多於調用其他函數),再搬移較高層函數;8;每次搬移後編譯測試;9.檢查,精簡每個類的接口;9.決定是否公開新類,如果你的確需要公開,舊要決定讓它成爲引用對象還是不可變的值對象。
7.4 Inline Class(將類內聯化)。
問題:某個類沒有做太多事情。
方法:將這個類的所有特性搬移到另一個類中,然後移除原類。
動機:正好與Extra Class相反,如果一個類不再承擔足夠責任,不再有單獨存在的理由,就需要將這個類塞進另一個類中。
做法:1.在目標類身上聲明類的public協議,並將其中所有函數委託至源類;2.修改所有源類引用點,改而引用目標類;3.編譯測試;4.運用Move Method和Move Field將源類的特性全部搬移到目標類。
7.5 Hide Delegate(隱藏“委託關係”)。
問題:客戶通過一個委託類來調用另一個對象。
方法:在服務類上建立客戶所需的所有函數,泳衣隱藏委託關係。
動機:將委託關係隱藏起來,防止委託關係發生變化,客戶也得相應變化,從而去除這種依賴。
做法:1.對於每一個委託關係中的函數,在服務對象端建立一個簡單的委託函數;2.調整客戶,令它只調用服務對象提供的函數;3.每次調整後編譯測試;4.如果將來不再有任何客戶需要取用受託類,便可移除服務對象中的相關訪問函數;5.編譯測試。
7.6 Remove Middle Man(移除中間人)。
問題:某個類做了過多的簡單委託動作。
方法:讓客戶直接調用受託類。
動機:在Hide Delegate中,封裝受託對象是有好處的,但是也是有代價的:每當客戶要使用受託類新特性,就必須在服務端添加一個簡單委託函數,隨着受託類功能增多,這個過程會讓人痛苦,服務類變成了一個“中間人”,此時應該移除中間人,讓客戶直接調用受託類。
做法:1.建立一個函數,泳衣獲得受託對象;2.對於每個委託函數,在服務類中刪除該函數,並讓需要調用該函數的客戶轉爲調用受託對象;3.處理每個委託函數後,編譯測試;
7.7 Introduce Foreign Method(引入外加函數)。
問題:你需要爲提供服務的類增加一個函數,但你無法修改這個類。
方法:在客戶類中建立一個函數,並以第一參數形式傳入一個服務類實例。
動機:使用一個類的時候需要一個新的服務,但是不能修改源碼,就得在客戶端編碼,補足函數所需功能。但是如果爲一個服務類建立了大量外加函數,就不該使用這個重構了,應該用Introduce Local Extension。
做法:1.在客戶類中建立一個函數用來提供所需功能;2.以服務類實例作爲該函數的第一個參數;3.將該函數註釋爲:“外加函數(foreign method)”,應在服務類實現。
7.8 Introduce Local Extension(引入本地擴展)。
問題:你需要爲服務類提供一些額外函數,但你無法修改這個類。
方法:建立一個新類,使它包含這些額外的函數。讓這個擴展品成爲源類的子類或包裝類。
動機:類的作者也無法預見未來,因此常常沒能爲後來者準備足夠有用的函數。如果無法修改源碼,需要兩個以上外加函數,就需要將這些函數組織在一起,放到一個恰當的地方。
做法:1.建立一個擴展類,將它作爲原始類的子類或者包裝類;2.在擴展類中加入轉型構造函數;3.在擴展類中加入新特性;4.根據需要,將原對象替換爲擴展對象;5.將針對原始類定義的所有外加函數搬移到擴展類中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章