1. 程式人生 > >重構筆記-00-重構手法預覽

重構筆記-00-重構手法預覽

重新組織程式碼

Extract Method提煉函式110

情況:你有一段程式碼可以被組織在一起並獨立出來。

概述:將這段程式碼放進一個獨立函式中,並讓函式名稱解釋該函式的用途。

Inline Method行內函數117

情況:一個函式的本體與名稱同樣清晰易懂。

概述:在函式呼叫點插入函式本體,然後移除該函式。

Inline Temp內聯臨時變數119

情況:你有一個臨時變數,只被一個簡單的表示式賦值一次,而它妨礙了其他重構手法。

概述:將所有對該變數的引用動作,替換為對它賦值的那個表示式自身。

Replace Temp with Query以查詢取代臨時變數

120

情況:你的程式以一個臨時變數儲存某一表達式的運算結果。

概述:將這個表示式提煉到一個獨立的函式中。將這個臨時變數的所有引用點替換為新函式呼叫。此後,新函式就可被其他函式使用。

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/StrategyState/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

情況:你有某個類做了太多的工作,其中一部分工作是以大量條件表示式完成的。

概述:建立繼承體系,以一個子類表示一種特殊情況。