
第一章 重構(gòu),第一個案例
- 如果你發(fā)現(xiàn)自己需要為程序添加一個特性,而代碼結(jié)構(gòu)使你無法很方便地達成目的,那就先重構(gòu)那個程序,使特性的添加比較容易進行,然后再添加特性。P7
- 重構(gòu)之前,首先檢查自己是否有一套可靠的測試機制。這些測試必須有自我檢驗?zāi)芰?。P8
- 重構(gòu)技術(shù)就是以微小的步伐修改程序。如果你犯下錯誤,很容易便可發(fā)現(xiàn)它。P13
- 任何一個傻瓜都能寫出計算機可以理解的代碼。唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員。P15
第二章 重構(gòu)原則
- 重構(gòu)(名詞):對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。P53
- 重構(gòu)(動詞):使用一系列重構(gòu)手法,在不改變可觀察行為的前提下,調(diào)整其結(jié)構(gòu)。P53
- 三次法則:事不過三,三則重構(gòu)。P58
第三章 代碼的壞味道
頁碼76
- 代碼壞味道:P76
- Duplicated Code(重復(fù)代碼)
- Long Method(過長函數(shù)):程序越長越難理解,小函數(shù)所帶來的全部利益——解釋能力、共享能力、選擇能力。
- Large Class(過大的類)
- Long Parameter List(過長參數(shù)列)
- Divergent Change(發(fā)散式變化):一個類受多種變化的影響。
- Shotgun Surgery(散彈式修改):一種變化引發(fā)多個類相應(yīng)修改。
- Feature Envy(依戀情結(jié))
- Data Clumps(數(shù)據(jù)泥團)
- Primitive Obsession(基本類型偏執(zhí))
- Switch Statements(switch驚悚出現(xiàn))
- Parallel Inheritance Hierarchies(平行繼承體系)
- Lazy Class(冗贅類)
- Speculative Generality(夸夸其談未來性)
- Temporary Field(令人迷惑的暫時字段)
- Message Chains(過度耦合的消息鏈)
- Middle Man(中間人)
- Inappropriate Intimacy()
- Alternative Classes with Different Interfaces(異曲同工的類)
- Incomplete Library Class(不完美的庫類)
- Data Class(純稚的數(shù)據(jù)類)
- Refused Bequest(被拒絕的遺贈)
- Comments(過多的注釋)
- 當你感覺需要撰寫注釋時,請先嘗試重構(gòu),試著讓所有注釋變得多余。P88
第四章 構(gòu)建測試體系
- 程序員把最多時間都耗在哪里,編寫代碼其實只占非常小得一部分。有些時間來決定下一步干什么,另一些時間花在設(shè)計上,最多的時間則是用來調(diào)試。P89
- 一套測試就是一個強大的bug偵測器,能夠大大縮減查找bug所需要的時間。P90
- 每當你收到bug報告,請先寫一個單元測試來暴露bug。P97
第六章 重新組織函數(shù)
- 小函數(shù)的粒度都很小,那么函數(shù)被復(fù)用的機會就越大;其次,這會使高層函數(shù)讀起來就像一系列注釋;再次,如果函數(shù)都是細粒度,那么函數(shù)的覆寫也會更容易些。只有當你能給小型函數(shù)很好地命名時,它們才能真正起作用。P110
Long Method(過長函數(shù))
- Extract Method(提煉函數(shù)) P110
- 你有一段代碼可以被組織在一起并獨立起來,將一部分代碼放進一個獨立函數(shù)中,并讓函數(shù)名稱解釋該函數(shù)的用途。
- Inline Method(內(nèi)聯(lián)函數(shù)) P117
- 一個函數(shù)的本體與名稱同樣清楚易懂。在函數(shù)調(diào)用點插入函數(shù)本體,然后移除該函數(shù)。
- Inline Temp(內(nèi)聯(lián)臨時變量) P119
- 你有一個臨時變量,只被一個簡單的表達式賦值一次,而它妨礙看其他重構(gòu)手法。將所有對該變量的引用動作,替換為對它賦值的那個表達式自身。
- Replace Temp with Query(以查詢?nèi)〈R時變量) P120
- 你的程序以一個臨時變量保存某一表達式的運算結(jié)果。將這個表達式提煉到一個獨立函數(shù)中。將這個臨時變量的所有引用點替換為對新函數(shù)的調(diào)用。此時新函數(shù)就可被其他函數(shù)使用。
- Introduce Explaining Variable(引入解釋性變量) P124
- 你有一個復(fù)雜的表達式。將該復(fù)雜的表達式(或其中的一部分)的結(jié)果放進一個臨時變量,以此變量名稱來解釋表達式用途。
- Split Temporary Variable(分解臨時變量) P128
- 你的程序有某個臨時變量被賦值超過一次,它既不是循環(huán)變量,也不被用于收集計算結(jié)果。針對每次賦值,創(chuàng)造一個獨立、對應(yīng)的臨時變量。
- Remove Assignments to Parameters(移除對參數(shù)的賦值) P131
- 代碼對一個參數(shù)進行賦值。以一個臨時變量取代該參數(shù)的位置。
- Replace Method with Method Object(以函數(shù)對象取代函數(shù)) P135
- 你有一個大型函數(shù),其中對局部變量的使用使你無法采用Extract Method(提取函數(shù))。將這個函數(shù)放進一個單獨的對象中,如此一來局部變量就成了對象內(nèi)的字段。然后你可以在同一個對象中將這個大型函數(shù)分解為多個小型函數(shù)。
- Substitute Algorithm(替換算法) P139
- 你想要把某個算法替換為另一個更清晰的算法。將函數(shù)本體替換為另一個算法。
第七章 在對象之間搬移特性
- 在對象的設(shè)計過程中,“決定把責任放在哪兒”即使不是最重要的事,也是最重要的事之一。P141
- “封裝”即使不是對象的最關(guān)鍵特征,也是最關(guān)鍵特征之一?!胺庋b”意味每個對象都應(yīng)該盡可能少了解系統(tǒng)的其他部分。如此一來,一旦發(fā)生變化,需要了解這一變化的對象就會比較少——這會使變化比較容易進行。P157
- 委托的代價:每當客戶要使用委托類的新特性時,你就必須在服務(wù)端添加一個簡單委托函數(shù)。P160
- Move Method(搬移函數(shù)) P142
- 你的程序中,有個函數(shù)與其所駐類之外的另外一個類進行更多交流:調(diào)用后者,或被后者調(diào)用。在該函數(shù)最常引用的類中建立一個有著類似行為的新函數(shù)。將就函數(shù)變成一個單純的委托函數(shù),或是將舊函數(shù)完全移除。
- Move Field(搬移字段) P146
- 你的程序中,某個字段被其所駐類之外的另一個類更多地用到。在目標類新建一個字段,修改源字段的所有用戶,令它們改用新字段。
- Extract Class(提煉類) P149
- 某個類做了應(yīng)該由兩個類做得事。建立一個新類,將相關(guān)的字段和函數(shù)從舊類搬移到新類。
- Inline Class(將類內(nèi)聯(lián)化) P154
- 某個類沒有做太多事情。將這個類的所有特性搬移到另外一個類中,然后移除原類。
- Hide Delegate(隱藏“委托關(guān)系”) P157
- 客戶通過一個委托類來調(diào)用另外一個對象。在服務(wù)類上建立客戶所需的所有函數(shù),用以隱藏委托關(guān)系。
- Remove Middle Man(移除中間人) P160
- 某個類做了過多的簡單委托動作。讓客戶直接調(diào)用受委托。
- Introduce Foreign Method(引入外加函數(shù)) P162
- 你需要為提供服務(wù)的類增加一個函數(shù),但你無法修改這個類。在客戶類中建立一個函數(shù),并以第一參數(shù)形式傳入一個服務(wù)類實例。
- Introduce Local Extension(引入本地擴展) P164
- 你需要為服務(wù)類提供一些額外函數(shù),但你無法修改這個類。建立一個新類,使它包含這些額外函數(shù)。讓這個擴展品成為源類的子類或包裝類。
第八章 重新組織數(shù)據(jù)
-
間接訪問變量的好處是,子類可以通過覆寫一個函數(shù)而改變獲取數(shù)據(jù)的途徑;它還支持更靈活的數(shù)據(jù)管理方式,例如延遲初始化(意思是:只有在需要用到某值時,才對它初始化)。P171
直接訪問變量的好處則是:代碼比較容易閱讀。閱讀代碼的時候,你不需要停下來說:“啊,這只是個取值函數(shù)”。
-
Self Encapsulate(自封裝字段)
- 你直接訪問一個字段,但與字段之間的耦合關(guān)系逐漸變得笨拙。為這個字段建立取值/設(shè)置函數(shù),并且只以這些函數(shù)來訪問字段。
-
Replace Data Value with Object(以對象取代數(shù)據(jù)值)
- 你有一個數(shù)據(jù)項,需要與其他數(shù)據(jù)和行為一起使用才有意義。將數(shù)據(jù)項變成對象。
-
Change Value to Reference(將值對象改為引用對象)
- 你從一個類衍生出許多彼此相等的實例,希望將它們替換為同一個對象。將這個值對象變成引用對象。
-
Change Reference to Value(將引用對象改為值對象)
- 你有一個引用對象,很小且不可變,而且不易管理。將它變成一個值對象。
-
Replace Array with Object(以對象取代數(shù)組)
- 你有一個數(shù)組,其中的元素各自代表不同的東西。以對象替換數(shù)組。對于數(shù)組中的每個元素,以一個字段來表示。
-
Duplicate Observed Data(復(fù)制“被監(jiān)視數(shù)據(jù)”)
- 你有一些領(lǐng)域數(shù)據(jù)置身于GUI控件中,而領(lǐng)域函數(shù)而要訪問這些數(shù)據(jù)。將該數(shù)據(jù)復(fù)制到一個領(lǐng)域?qū)ο笾?。建立一個Oberver模式,用以同步領(lǐng)域?qū)ο蠛虶UI對象內(nèi)的重復(fù)數(shù)據(jù)。
-
Change Unidirectional Association to Bidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))
- 兩個類都需要使用對方特性,但其間只有一條單向連接。添加一個反向指針,并使修改函數(shù)能夠同時更新兩條連接。
-
Chnage Bidirectional Association to Unidirectional(將雙向關(guān)聯(lián)改為單向關(guān)聯(lián))
- 兩個類之間有雙向關(guān)聯(lián),但其中一個類如今不再需要另外一個類的特性。兩個類之間有雙向關(guān)聯(lián),但其中一個類如今不再需要另外一類的特性。去除不必要的關(guān)聯(lián)。
-
Replace Magic Number with Symbolic Constant(以字面常量取代魔法數(shù))
- 你有一個字面數(shù)值,帶有特別含義。創(chuàng)造一個常量,根據(jù)其意義為它命名,并將上述的字面數(shù)值替換為這個常量。
-
Encapsulate Field(封裝字段)
- 你的類中存在一個public字段。將它聲明為private, 并提供相應(yīng)的訪問函數(shù)。
-
Encapsulate Collection(封裝集合)
- 有個函數(shù)返回一個集合。讓這個函數(shù)返回該集合的一個只讀副本,并在這個類中提供添加、移除集合元素的函數(shù)。
-
Replace Record with Data Class(以數(shù)據(jù)類取代記錄)
- 你需要面對傳統(tǒng)編程環(huán)境中的記錄結(jié)構(gòu)。為該記錄創(chuàng)建一個“啞”數(shù)據(jù)對象。
-
Replace Type Code with Class(以類取代類型碼)
- 類之中有一個數(shù)值類型碼,但它并不影響類的行為。以一個新的類替換該數(shù)值類型碼。
-
Replace Type Code with Subclasses(以子類取代類型碼)
- 你有一個不可變的類型碼,它會影響類的行為。以子類取代這個類型碼。
-
Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
- 你有一個類型碼,它會影響類的行為,但你無法通過繼承手法消除它。以狀態(tài)對象取代類型碼。
-
Replace Subclass with Fields(以字段取代子類)
- 你的各個子類的唯一差別只在“返回常量數(shù)據(jù)”的函數(shù)身上。修改這些函數(shù),使它們返回超類中的某個(新增)字段,然后銷毀子類。
第九章 簡化條件表達式
- Decompose Conditional(分解條件表達式)
- 你有一個復(fù)雜的條件(if-then-else)語句。從if、then、else三個段落中分別提煉獨立函數(shù)。
- Consolidate Conditional Expression(合并條件表達式)
- 你有一系列條件測試,都得到相同結(jié)果。將這些測試合并為一個條件表達式,并將這個條件表達式提煉成為一個獨立函數(shù)。
- Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片段)
- 在條件表達式的每個分支上有著相同的一段代碼。將這段重復(fù)代碼搬移到條件表達式之外。
- Remove Control Flag(移除控制標記)
- 在一系列布爾表達式中,某個變量帶有“控制標記”(control flag)的作用。以break語句或return語句取代控制標記。
- Replace Nested Conditional with Guard Clauses(以衛(wèi)語句取代嵌套條件表達式)
- 函數(shù)中的條件邏輯使人難以看清正常的執(zhí)行路徑。使用衛(wèi)語句表現(xiàn)所有特殊情況。
- Replace Conditional with Polymorphism(以多態(tài)取代條件表達式)
- 你手上有個條件表達式,它根據(jù)對象類型的不同而選擇不同的行為。將這個條件表達式的每個分支放進一個子類內(nèi)的覆寫函數(shù)中,然后將原始函數(shù)聲明為抽象函數(shù)。
- Introduce Null Object(引入Null對象)
- 你需要再三檢查對象是否為null。將null值替換為null對象。
- Introduce Assertion(引入斷言)
- 某一段代碼需要對程序狀態(tài)做出某種假設(shè)。以斷言明確表現(xiàn)這種假設(shè)。
第十章 簡化函數(shù)調(diào)用
- Rename Method(函數(shù)改名)
- 函數(shù)的名稱未能揭示函數(shù)的用途。修改函數(shù)名稱。
- Add Parameter(添加參數(shù))
- 某個函數(shù)需要從調(diào)用端得到更多信息。為此函數(shù)添加一個對象參數(shù),讓該對象帶進函數(shù)所需信息。
- Remove Parameter(移除函數(shù))
- 函數(shù)本體不再需要某個參數(shù)。將該參數(shù)去除。
- Separate Query fom Modifier(將查詢函數(shù)和修改函數(shù)分離)
- 某個函數(shù)即返回對象狀態(tài)值,又修改對象狀態(tài)。建立兩個不同的函數(shù),其中一個負責查詢,另一個負責修改。
- Parameterize Method(令函數(shù)攜帶參數(shù))
- 若干函數(shù)做了類似的工作,但在函數(shù)本體中卻包含了不同的值。
- Replace Parameter with Explicit Methods(以明確函數(shù)取代參數(shù))
- 你有一個函數(shù),其中完全取決于參數(shù)值而采取不同行為。針對該參數(shù)的每一個可能值,建立一個獨立函數(shù)。
- Preserve Whole Object(保持對象完整)
- 你從某個對象中取出若干值,將他們作為某一次函數(shù)調(diào)用時的參數(shù)。改為傳遞整個對象。
- Replace Parameter with Methods(以函數(shù)取代參數(shù))
- 對象調(diào)用某個函數(shù),并將所得結(jié)果作為參數(shù),傳遞給另一個函數(shù)。而接受該參數(shù)的函數(shù)本身也能夠調(diào)用前一個函數(shù)。讓參數(shù)接受者去除該項參數(shù),并直接調(diào)用前一個函數(shù)。
- Introduce Parameter Object(引入?yún)?shù)對象)
- 某些參數(shù)總是很自然地同時出現(xiàn)。以一個對象取代這些參數(shù)。
- Remove Setting Method(移除設(shè)置函數(shù))
- 類中的某個字段應(yīng)該在對象創(chuàng)建時被設(shè)值,然后就不再改變。去掉該字段的所有設(shè)值函數(shù)。
- Hide Method(隱藏函數(shù))
- 有一個函數(shù),從來沒有被其他任何類用到。將這個函數(shù)修改為private。
- Replace Constructor with Factory Method(以工廠函數(shù)取代構(gòu)造函數(shù))
- 你希望在創(chuàng)建對象時不僅僅是做簡單的構(gòu)建動作。將構(gòu)造函數(shù)替換為工廠函數(shù)。
- Encapsulate Downcase(封裝向下轉(zhuǎn)型)
- 某個函數(shù)返回的對象,需要由函數(shù)調(diào)用者執(zhí)行向下轉(zhuǎn)型(downcase)。將向下轉(zhuǎn)型動作移到函數(shù)中。
- Replace Error Code with Exception(以異常取代錯誤碼)
- 某個函數(shù)返回一個特定的代碼,用以表示某種錯誤情況。改用異常。
- Replace Exception with Test(以測試取代異常)
- 面對一個調(diào)用者可以預(yù)見檢查的條件,你拋出了一個異常。修改調(diào)用者,使它在調(diào)用函數(shù)之前先做檢查。
第十一章 處理概括關(guān)系
- Pull Up Field(字段上移)
- 兩個子類擁有相同的字段。將該字段移至超類。
- Pull Up Method(函數(shù)上移)
- 有些函數(shù),在各個子類中產(chǎn)生完全相同的結(jié)果。將該函數(shù)移至超類。
- Pull Up Contrructor Body(構(gòu)造函數(shù)本體上移)
- 你在各個子類中擁有一些構(gòu)造函數(shù),它們的本體幾乎完全一致。在超類中新建一個構(gòu)造函數(shù),并在子類構(gòu)造函數(shù)中調(diào)用它。
- Push Down Method(函數(shù)下移)
- 超類中的某個函數(shù)只與部分(而非全部)子類有關(guān)。將這個函數(shù)移到相關(guān)的那些子類去。
- Push Down Field(字段下移)
- 超類中的某個字段只被部分(而非全部)子類用到。將這個字段移到需要它的那些子類去。
- Extract Subclass(提煉子類)
- 類中的某些特性只被某些(而非全部)實例用到。新建一個子類,將上面所說的那一部分特性移到子類中。
- Extract Superclass(提煉超類)
- 兩個類有相似特性。為兩個類建立一個超類,將相同特性移至超類。
- Extract Interface(提煉接口)
- 若干客戶使用類接口中的同一子集,或者兩個類的接口有部分相同。將相同的子集提煉到一個獨立接口中。
- Collapse Hierarchy(折疊繼承體系)
- 超類和子類之間無太大區(qū)別。將他們合為一體。
- Form TemPlate Method(塑造模板函數(shù))
- 你有一些子類,其中相應(yīng)的某些函數(shù)以相同順序執(zhí)行類似的操作,但各個操作的細節(jié)上有所不同。將這些操作分別放進獨立函數(shù)中,并保持它們都有相同簽名,于是原函數(shù)也就變得相同了。然后將原函數(shù)上移至超類。
- Replace Inheritance with Delegation(以委托取代繼承)
- 某個子類只使用超類接口中德一部分,或是根本不需要繼承而來的數(shù)據(jù)。在子類中新建一個字段用以保存超類;調(diào)整子類函數(shù),令它改而委托超類;然后去掉兩者之間的繼承關(guān)系。
- Replace Delegation with Inheritance(以繼承取代委托)
- 你在兩個類之間使用委托關(guān)系,并經(jīng)常為整個接口編寫許多極簡單的委托函數(shù)。讓委托類繼承受托類。
第十二章 大型重構(gòu)
- Tease Apart Inheritance(梳理并分解繼承體系)
- 某個繼承體系同時承擔兩項責任。建立兩個繼承體系,并通過委托關(guān)系讓其中一個可以調(diào)用另外一個。
- Convert Procedural Design to Objects(將過程化設(shè)計轉(zhuǎn)化為對象設(shè)計)
- 你手上有一些傳統(tǒng)過程化風格的代碼。將數(shù)據(jù)記錄變成對象,將大塊的行為分成小塊,并將行為移入相關(guān)對象之中。
- Separate Domain from Presentation(將領(lǐng)域和表述/顯示分離)
- 某些GUI類之中包含了領(lǐng)域邏輯。將領(lǐng)域邏輯分離出來,為他們建立獨立的領(lǐng)域類。
- Extract Hierarchy(提煉繼承體系)
- 你有某個類做了太多工作,其中一部分工作時以大量條件表達式完成的。建立繼承體系,以一個類表示一種特殊情況。