重構筆記-00-重構手法預覽
重新組織程式碼
Extract Method(提煉函式)110
情況:你有一段程式碼可以被組織在一起並獨立出來。
概述:將這段程式碼放進一個獨立函式中,並讓函式名稱解釋該函式的用途。
Inline Method(行內函數)117
情況:一個函式的本體與名稱同樣清晰易懂。
概述:在函式呼叫點插入函式本體,然後移除該函式。
Inline Temp(內聯臨時變數)119
情況:你有一個臨時變數,只被一個簡單的表示式賦值一次,而它妨礙了其他重構手法。
概述:將所有對該變數的引用動作,替換為對它賦值的那個表示式自身。
Replace Temp with Query(以查詢取代臨時變數)
情況:你的程式以一個臨時變數儲存某一表達式的運算結果。
概述:將這個表示式提煉到一個獨立的函式中。將這個臨時變數的所有引用點替換為新函式呼叫。此後,新函式就可被其他函式使用。
Introduce Explaining Variable(引入解釋性變數)124
情況:你有一個複雜的表示式。
概述:將該複雜表示式(或其中一部分)的結果放進臨時變數,以此變數名稱來解釋表示式用途。
Split Temporary Variable(分解臨時變數)128
情況:你的程式有某個臨時變數被賦值超過一次,它既不是迴圈變數,也不是被用於收集計算結果。
概述:針對每次賦值,創造一個獨立、對應的臨時變數。
Remove Assignments to Parameters(移除對引數的賦值)134
情況:程式碼對一個引數進行賦值。
概述:以一個臨時變數取代該引數的位置。
Replace Method with Method Object(以函式物件取代函式)135
情況:你有一個大型函式,其中對區域性變數的使用使你無法採用Extract Method(110)。
概述:將這個函式放進一個單獨物件中,如此一來區域性變數就成了物件內的欄位。然後你可以在同一個物件中將這個大型函式分解為多個小型函式。
Substitute Algorithm(替換演算法)139
情況:你想把某個演算法替換為另一個更清晰的演算法。
概述:將函式本體替換為另一個演算法。
在物件之間搬移特性
Move Method(搬移函式)142
情況:你的程式中,有個函式與其所駐類之外的另一個類進行更多交流;呼叫後者,或被後者呼叫。
概述:在該函式最常引用的類中建立一個有著類似行為的新函式。將舊函式變成一個單純的委託函式,或是將舊函式完全移除。
Move Field(搬移欄位)146
情況:你的程式中,某個欄位被其所駐類之外的另一個類更多地用到。
概述:在目標類新建一個欄位,修改源欄位的所用使用者,令它們改用新欄位。
Extract Class(提煉類)149
情況:某個類做了應該由兩個類做的事。
概述:建立一個新類,將相關的欄位和函式從舊類搬移到新類。
Inline Class(將類內聯化)154
情況:某個類沒有做太多事情。
概述:將這個類的所有特性搬移到另一個類中,然後移除原類。
Hide Delegate(隱藏“委託關係”)157
情況:客戶通過一個委託類來呼叫另一個物件。
概述:在服務類上建立客戶需要的所有函式,用以隱藏委託關係。
Remove Middle Man(移除中間人)160
情況:某個類做了過多的簡單委託動作。
概述:讓客戶直接呼叫受託類。
Introduce Foreign Method(引入外加函式)162
情況:你需要為提供服務的類增加一個函式,但你無法修改這個類。
概述:在客戶類中建立一個函式,並以第一引數形式傳入一個服務類例項。
Introduce Local Extension(引入本地擴充套件)164
情況:你需要為服務類提供一些額外函式,但你無法修改這個類。
概述:建立一個新類,使它包含這些額外函式。讓這個擴充套件品成為源類的子類或包裝類。
重新組織資料
Self Encapsulate Fidld(自封裝欄位)171
情況:你直接訪問一個欄位,但與欄位之間的耦合關係逐漸變得笨拙。
概述:為這個欄位建立取值/設值函式,並且只以這些函式來訪問欄位。
Replace Data Value with Object(以物件取代資料值)175
情況:你有一個數據項,需要與其他資料和行為一起使用才有意義。
概述:將資料項變成物件。
Change Value to Reference(將值物件改為引用物件)179
情況:你從一個類衍生出許多彼此相等的例項,希望將它們替換為同一個物件。
概述:將這個值物件變成引用物件。
Change Reference to Value(將引用物件改為值物件)183
情況:你有一個引用物件,很小且不可變,而且不易管理。
概述:將它變成一個值物件。
Replace Array with Object(已物件取代陣列)186
情況:你有一個數組,其中的元素各自代表不同的東西。
概述:以物件替換陣列。對於陣列中的每個元素,以一個欄位來表示。
Duplicate Observed Data(複製“被監視資料”)189
情況:你有一些領域資料置身於GUI控制元件中,而領域函式需要訪問這些資料。
概述:將該資料複製到一個領域物件中。建立一個Observed模式,用以同步領域物件和GUI物件內的重複資料。
Change Unidirectional Association to Bidirectional(將單向關聯改為雙向關聯)197
情況:兩個類都需要使用對方特性,但其間只有一條單向連線。
概述:新增一個反向指標,並使修改函式能夠同時更新兩條連線。
Change Bidirectional Association to Unidirectional(將雙向關聯改為單向關聯)200
情況:兩個類之間有雙向關聯,但其中一個類如今不再需要另一個類的特性。
概述:去除不必要的關聯。
Replace Magic Number with Symbolic Constant(以字面常量取代魔法數)204
情況:你有一個字面數值,帶有特別含義。
概述:建立一個常量,根據其意為它命名,並將上述的字面數值替換為這個常量。
Encapsulate Field(封裝欄位)206
情況:你的類中存在一個public欄位。
概述:將它宣告為private,並提供相應的訪問函式。
Encapsulate Collection(封裝集合)208
情況:有個函式返回一個集合。
概述:讓這個函式返回該集合的一個只讀副本,並在這個類中提供新增/移除集合元素的函式。
Replace Record with Data Class(以資料類取代記錄)217
情況:你需要面對傳統程式設計環境中的記錄結構。
概述:為該記錄建立一個“啞”資料物件。
Replace Type Code with Class(以類取代型別碼)218
情況:類之中有一個數值型別碼,但它並不影響類的行為。
概述:以一個新的類替換該數值型別碼。
Replace Type Code with Subclasses(以子類取代型別碼)223
情況:你有一個不可變得型別碼,它會影響類的行為。
概述:以子類取代這個型別碼。
Replace Type Code with State/Strategy(以State/Strategy取代型別碼)227
情況:你有一個型別碼,它會影響類的行為,但你無法通過繼承手法消除它。
概述:以狀態物件取代型別碼。
Replace Subclass with Fields(以欄位取代子類)232
情況:你的各個子類的唯一差別只在“返回常量資料”的函式身上。
概述:修改這些函式,使它們返回超類中的某個(新增)欄位,然後銷燬子類。
簡化條件表示式
Decompose Conditional(分解條件表示式)238
情況:你有一個複雜的條件(if-then-else)語句。
概述:從if、then、else三個段落中分別提煉出獨立的函式。
Consolidate Conditional Expression(合併條件表示式)240
情況:你有一系列條件測試,都得到相同結果。
概述:將這些測試合併為一個條件表示式,並將這個條件表示式提煉為一個獨立函式。
Consolidate Duplicate Conditional Fragments(合併重複的條件片段)243
情況:在條件表示式的每個分支上有著相同的一段程式碼。
概述:將這段重複程式碼搬移到條件表示式之外。
Remove Control Flag(移除控制標記)245
情況:在一系列布林表示式中,某個變數帶有“控制標記”(control flag)的作用。
概述:以break語句或return語句取代控制標記。
Replace Nested Conditional with Guard Clauses(以衛語句取代巢狀條件表示式)250
情況:函式中的條件邏輯使人難以看清正常的執行路徑。
概述:使用衛語句表現所有特殊情況。
Replace Conditional with Polymorphism(以多型取代條件表示式)255
情況:你手上有個條件表示式,它根據物件型別的不同而選擇不同的行為。
概述:將這個條件表示式的每個分支放進一個子類內的複寫函式中,然後將原始函式宣告為抽象函式。
Introduce Null Object(引入Null物件)260
情況:你需要再三檢查某個物件是否為Null。
概述:將Null值替換為Null物件。
Introduce Assertion(引入斷言)267
情況:某一段程式碼需要對程式狀態做出某種假設。
概述:以斷言明確表現這種假設。
簡化函式呼叫
Rename Method(函式改名)273
情況:函式名稱未能揭示函式的用途。
概述:修改函式名稱。
Add Parameter(新增引數)275
情況:某個函式需要從呼叫端得到更多資訊。
概述:為此函式新增一個物件引數,讓該物件帶進函式所需資訊。
Remove Parameter(移除引數)277
情況:函式本體不再需要某個引數。
概述:將該引數去除。
Separate Query from Modifier(將查詢函式和修改函式分離)279
情況:某個函式既返回物件狀態值,又修改物件狀態。
概述:建立兩個不同的函式,其中一個複雜查詢,另一個負責修改。
Parameterize Method(令函式攜帶引數)283
情況:若干函式做了類似的工作,但在函式本體中卻包含了不同的值。
概述:建立單一函式,以引數表達那些不同的值。
Replace Parameter with Explicit Methods(以明確函式取代引數)285
情況:你有一個函式,其中完全取決於引數值而採取不同行為。
概述:針對該引數的每一個可能值,建立一個獨立函式。
Preserve Whole Object(保持物件完整)288
情況:你從某個物件中取出若干值,將它們作為某一次函式呼叫時的引數。
概述:改為傳遞整個物件。
Replace Parameter with Methods(以函式取代引數)292
情況:物件呼叫某個函式,並將所得結果作為引數,傳遞給另一個函式。而接受該引數的函式本身也能夠呼叫前一個函式。
概述:讓引數接受者去除該項引數,並直接呼叫前一個函式。
Introduce Parameter Object(引入引數物件)295
情況:某些引數總是很自然地同時出現。
概述:以一個物件取代這些引數。
Remove Setting Method(移除設值函式)300
情況:類中的某個欄位應該在物件建立時被設值,然後就不再改變。
概述:去掉該欄位的所有設值函式。
Hide Method(隱藏函式)303
情況:有一個函式,從來沒有被其他任何類用到。
概述:將這個函式修改為private。
Replace Constructor with Factory Method(以工廠函式取代建構函式)304
情況:你希望在建立物件時不僅僅是做簡單的建構動作。
概述:將建構函式替換為工廠函式。
Encapsulate Downcast(封裝向下轉型)308
情況:某個函式返回的物件,需要由函式呼叫者執行向下轉型(downcast)。
概述:將向下轉型動作移到函式中。
Replace Error Code with Exception(以異常取代錯誤碼)310
情況:某個函式返回一個特定的程式碼,用以表示某種錯誤情況。
概述:改用異常。
Replace Exception with Test(以測試取代異常)315
情況:面對一個呼叫者可以預先檢查的條件,你丟擲了一個異常。
概述:修改呼叫者,使它在呼叫函式之前先做檢查。
處理概括關係
Pull Up Field(欄位上移)320
情況:兩個子類擁有相同的欄位。
概述:將該欄位移至超類。
Pull Up Method(函式上移)322
情況:有些函式,在各個子類中產生完全相同的結果。
概述:將該函式移至超類。
Pull Up Constructor Body(建構函式本體上移)325
情況:你在各個子類中擁有一些建構函式,它們的本體幾乎完全一致。
概述:在超類中新建一個建構函式,並在子類建構函式中呼叫它。
Push Down Method(函式下移)328
情況:超類中的某個函式只與部分(而非全部)子類有關。
概述:將這個函式移到相關的那些子類去。
Push Down Field(欄位下移)329
情況:超類中的某個欄位只被部分(而非全部)子類用到。
概述:將這個欄位移動到需要它的那些子類去。
Extract Subclass(提煉子類)330
情況:類中的某些特性只被某些(而非全部)例項用到。
概述:新建一個子類,將上面所說的那一部分特性移到子類中。
Extract Superclass(提煉超類)336
情況:兩個類有相似特性。
概述:為這兩個類建立一個超類,將相同特性移至超類。
Extract Interface(提煉介面)341
情況:若干客戶使用類介面中的同一子集,或者兩個類的介面有部分相同。
概述:將相同的子集提煉到一個獨立介面中。
Collapse Hierarchy(摺疊繼承體系)344
情況:超類和子類之間無太大區別。
概述:將它們合為一體。
Form TemPlate Method(塑造模板函式)345
情況:你有一些子類,其中相應的某些函式以相同順序執行類似的操作,但各個操作的細節上有所不同。
概述:將這些操作分別放進獨立函式中,並保持它們都有相同的簽名,於是原函式也就變得相同了。然後將原函式上移至超類。
Replace Inheritance with Delegation(以委託取代繼承)352
情況:某個子類只使用超類介面中的一部分,或是根本不需要繼承而來的資料。
概述:在子類中新建一個欄位用以儲存超類;調整子類函式,令它改而委託超類;然後去掉兩者之間的繼承關係。
Replace Delegation with Inheritance(以繼承取代委託)355
情況:你在兩個類之間使用委託關係,並經常為整個介面編寫許多極簡單的委託函式。
概述:讓委託類繼承受託類。
大型重構
Tease Apart Inheritance(梳理並分解繼承體系)362
情況:某個繼承體系同事承擔兩項責任。
概述:建立兩個繼承體系,並通過委託關係讓其中一個可以呼叫另一個。
Convert Procedural Design to Object(將過程化設計轉化為物件設計)368
情況:你手上有一些傳統過程化風格的程式碼。
概述:將資料記錄變成物件,將大塊的行為分成小塊,並將行為移入相關物件之中。
Separate Domain from Presentation(將領域和表述/顯示分離)370
情況:某些GUI類之中包含了領域邏輯。
概述:將領域邏輯分離出來,為它們建立獨立的領域類。
Extract Hierarchy(提煉繼承體系)375
情況:你有某個類做了太多的工作,其中一部分工作是以大量條件表示式完成的。
概述:建立繼承體系,以一個子類表示一種特殊情況。