重構(gòu)-讀書筆記

重構(gòu).jpg

第一章 重構(gòu),第一個案例

  1. 如果你發(fā)現(xiàn)自己需要為程序添加一個特性,而代碼結(jié)構(gòu)使你無法很方便地達成目的,那就先重構(gòu)那個程序,使特性的添加比較容易進行,然后再添加特性。P7
  2. 重構(gòu)之前,首先檢查自己是否有一套可靠的測試機制。這些測試必須有自我檢驗?zāi)芰?。P8
  3. 重構(gòu)技術(shù)就是以微小的步伐修改程序。如果你犯下錯誤,很容易便可發(fā)現(xiàn)它。P13
  4. 任何一個傻瓜都能寫出計算機可以理解的代碼。唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員。P15

第二章 重構(gòu)原則

  1. 重構(gòu)(名詞):對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。P53
  2. 重構(gòu)(動詞):使用一系列重構(gòu)手法,在不改變可觀察行為的前提下,調(diào)整其結(jié)構(gòu)。P53
  3. 三次法則:事不過三,三則重構(gòu)。P58

第三章 代碼的壞味道

頁碼76
  1. 代碼壞味道:P76
    1. Duplicated Code(重復(fù)代碼)
    2. Long Method(過長函數(shù)):程序越長越難理解,小函數(shù)所帶來的全部利益——解釋能力、共享能力、選擇能力。
    3. Large Class(過大的類)
    4. Long Parameter List(過長參數(shù)列)
    5. Divergent Change(發(fā)散式變化):一個類受多種變化的影響。
    6. Shotgun Surgery(散彈式修改):一種變化引發(fā)多個類相應(yīng)修改。
    7. Feature Envy(依戀情結(jié))
    8. Data Clumps(數(shù)據(jù)泥團)
    9. Primitive Obsession(基本類型偏執(zhí))
    10. Switch Statements(switch驚悚出現(xiàn))
    11. Parallel Inheritance Hierarchies(平行繼承體系)
    12. Lazy Class(冗贅類)
    13. Speculative Generality(夸夸其談未來性)
    14. Temporary Field(令人迷惑的暫時字段)
    15. Message Chains(過度耦合的消息鏈)
    16. Middle Man(中間人)
    17. Inappropriate Intimacy()
    18. Alternative Classes with Different Interfaces(異曲同工的類)
    19. Incomplete Library Class(不完美的庫類)
    20. Data Class(純稚的數(shù)據(jù)類)
    21. Refused Bequest(被拒絕的遺贈)
    22. Comments(過多的注釋)
  2. 當你感覺需要撰寫注釋時,請先嘗試重構(gòu),試著讓所有注釋變得多余。P88

第四章 構(gòu)建測試體系

  1. 程序員把最多時間都耗在哪里,編寫代碼其實只占非常小得一部分。有些時間來決定下一步干什么,另一些時間花在設(shè)計上,最多的時間則是用來調(diào)試。P89
  2. 一套測試就是一個強大的bug偵測器,能夠大大縮減查找bug所需要的時間。P90
  3. 每當你收到bug報告,請先寫一個單元測試來暴露bug。P97

第六章 重新組織函數(shù)

  1. 小函數(shù)的粒度都很小,那么函數(shù)被復(fù)用的機會就越大;其次,這會使高層函數(shù)讀起來就像一系列注釋;再次,如果函數(shù)都是細粒度,那么函數(shù)的覆寫也會更容易些。只有當你能給小型函數(shù)很好地命名時,它們才能真正起作用。P110
Long Method(過長函數(shù))
  1. Extract Method(提煉函數(shù)) P110
    • 你有一段代碼可以被組織在一起并獨立起來,將一部分代碼放進一個獨立函數(shù)中,并讓函數(shù)名稱解釋該函數(shù)的用途。
  2. Inline Method(內(nèi)聯(lián)函數(shù)) P117
    • 一個函數(shù)的本體與名稱同樣清楚易懂。在函數(shù)調(diào)用點插入函數(shù)本體,然后移除該函數(shù)。
  3. Inline Temp(內(nèi)聯(lián)臨時變量) P119
    • 你有一個臨時變量,只被一個簡單的表達式賦值一次,而它妨礙看其他重構(gòu)手法。將所有對該變量的引用動作,替換為對它賦值的那個表達式自身。
  4. Replace Temp with Query(以查詢?nèi)〈R時變量) P120
    • 你的程序以一個臨時變量保存某一表達式的運算結(jié)果。將這個表達式提煉到一個獨立函數(shù)中。將這個臨時變量的所有引用點替換為對新函數(shù)的調(diào)用。此時新函數(shù)就可被其他函數(shù)使用。
  5. Introduce Explaining Variable(引入解釋性變量) P124
    • 你有一個復(fù)雜的表達式。將該復(fù)雜的表達式(或其中的一部分)的結(jié)果放進一個臨時變量,以此變量名稱來解釋表達式用途。
  6. Split Temporary Variable(分解臨時變量) P128
    • 你的程序有某個臨時變量被賦值超過一次,它既不是循環(huán)變量,也不被用于收集計算結(jié)果。針對每次賦值,創(chuàng)造一個獨立、對應(yīng)的臨時變量。
  7. Remove Assignments to Parameters(移除對參數(shù)的賦值) P131
    • 代碼對一個參數(shù)進行賦值。以一個臨時變量取代該參數(shù)的位置。
  8. Replace Method with Method Object(以函數(shù)對象取代函數(shù)) P135
    • 你有一個大型函數(shù),其中對局部變量的使用使你無法采用Extract Method(提取函數(shù))。將這個函數(shù)放進一個單獨的對象中,如此一來局部變量就成了對象內(nèi)的字段。然后你可以在同一個對象中將這個大型函數(shù)分解為多個小型函數(shù)。
  9. Substitute Algorithm(替換算法) P139
    • 你想要把某個算法替換為另一個更清晰的算法。將函數(shù)本體替換為另一個算法。

第七章 在對象之間搬移特性

  1. 在對象的設(shè)計過程中,“決定把責任放在哪兒”即使不是最重要的事,也是最重要的事之一。P141
  2. “封裝”即使不是對象的最關(guān)鍵特征,也是最關(guān)鍵特征之一?!胺庋b”意味每個對象都應(yīng)該盡可能少了解系統(tǒng)的其他部分。如此一來,一旦發(fā)生變化,需要了解這一變化的對象就會比較少——這會使變化比較容易進行。P157
  3. 委托的代價:每當客戶要使用委托類的新特性時,你就必須在服務(wù)端添加一個簡單委托函數(shù)。P160
  4. Move Method(搬移函數(shù)) P142
    • 你的程序中,有個函數(shù)與其所駐類之外的另外一個類進行更多交流:調(diào)用后者,或被后者調(diào)用。在該函數(shù)最常引用的類中建立一個有著類似行為的新函數(shù)。將就函數(shù)變成一個單純的委托函數(shù),或是將舊函數(shù)完全移除。
  5. Move Field(搬移字段) P146
    • 你的程序中,某個字段被其所駐類之外的另一個類更多地用到。在目標類新建一個字段,修改源字段的所有用戶,令它們改用新字段。
  6. Extract Class(提煉類) P149
    • 某個類做了應(yīng)該由兩個類做得事。建立一個新類,將相關(guān)的字段和函數(shù)從舊類搬移到新類。
  7. Inline Class(將類內(nèi)聯(lián)化) P154
    • 某個類沒有做太多事情。將這個類的所有特性搬移到另外一個類中,然后移除原類。
  8. Hide Delegate(隱藏“委托關(guān)系”) P157
    • 客戶通過一個委托類來調(diào)用另外一個對象。在服務(wù)類上建立客戶所需的所有函數(shù),用以隱藏委托關(guān)系。
  9. Remove Middle Man(移除中間人) P160
    • 某個類做了過多的簡單委托動作。讓客戶直接調(diào)用受委托。
  10. Introduce Foreign Method(引入外加函數(shù)) P162
    • 你需要為提供服務(wù)的類增加一個函數(shù),但你無法修改這個類。在客戶類中建立一個函數(shù),并以第一參數(shù)形式傳入一個服務(wù)類實例。
  11. Introduce Local Extension(引入本地擴展) P164
    • 你需要為服務(wù)類提供一些額外函數(shù),但你無法修改這個類。建立一個新類,使它包含這些額外函數(shù)。讓這個擴展品成為源類的子類或包裝類。

第八章 重新組織數(shù)據(jù)

  1. 間接訪問變量的好處是,子類可以通過覆寫一個函數(shù)而改變獲取數(shù)據(jù)的途徑;它還支持更靈活的數(shù)據(jù)管理方式,例如延遲初始化(意思是:只有在需要用到某值時,才對它初始化)。P171

    直接訪問變量的好處則是:代碼比較容易閱讀。閱讀代碼的時候,你不需要停下來說:“啊,這只是個取值函數(shù)”。

  2. Self Encapsulate(自封裝字段)

    • 你直接訪問一個字段,但與字段之間的耦合關(guān)系逐漸變得笨拙。為這個字段建立取值/設(shè)置函數(shù),并且只以這些函數(shù)來訪問字段。
  3. Replace Data Value with Object(以對象取代數(shù)據(jù)值)

    • 你有一個數(shù)據(jù)項,需要與其他數(shù)據(jù)和行為一起使用才有意義。將數(shù)據(jù)項變成對象。
  4. Change Value to Reference(將值對象改為引用對象)

    • 你從一個類衍生出許多彼此相等的實例,希望將它們替換為同一個對象。將這個值對象變成引用對象。
  5. Change Reference to Value(將引用對象改為值對象)

    • 你有一個引用對象,很小且不可變,而且不易管理。將它變成一個值對象。
  6. Replace Array with Object(以對象取代數(shù)組)

    • 你有一個數(shù)組,其中的元素各自代表不同的東西。以對象替換數(shù)組。對于數(shù)組中的每個元素,以一個字段來表示。
  7. 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ù)。
  8. Change Unidirectional Association to Bidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))

    • 兩個類都需要使用對方特性,但其間只有一條單向連接。添加一個反向指針,并使修改函數(shù)能夠同時更新兩條連接。
  9. 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)。
  10. Replace Magic Number with Symbolic Constant(以字面常量取代魔法數(shù))

    • 你有一個字面數(shù)值,帶有特別含義。創(chuàng)造一個常量,根據(jù)其意義為它命名,并將上述的字面數(shù)值替換為這個常量。
  11. Encapsulate Field(封裝字段)

    • 你的類中存在一個public字段。將它聲明為private, 并提供相應(yīng)的訪問函數(shù)。
  12. Encapsulate Collection(封裝集合)

    • 有個函數(shù)返回一個集合。讓這個函數(shù)返回該集合的一個只讀副本,并在這個類中提供添加、移除集合元素的函數(shù)。
  13. Replace Record with Data Class(以數(shù)據(jù)類取代記錄)

    • 你需要面對傳統(tǒng)編程環(huán)境中的記錄結(jié)構(gòu)。為該記錄創(chuàng)建一個“啞”數(shù)據(jù)對象。
  14. Replace Type Code with Class(以類取代類型碼)

    • 類之中有一個數(shù)值類型碼,但它并不影響類的行為。以一個新的類替換該數(shù)值類型碼。
  15. Replace Type Code with Subclasses(以子類取代類型碼)

    • 你有一個不可變的類型碼,它會影響類的行為。以子類取代這個類型碼。
  16. Replace Type Code with State/Strategy(以State/Strategy取代類型碼)

    • 你有一個類型碼,它會影響類的行為,但你無法通過繼承手法消除它。以狀態(tài)對象取代類型碼。
  17. Replace Subclass with Fields(以字段取代子類)

    • 你的各個子類的唯一差別只在“返回常量數(shù)據(jù)”的函數(shù)身上。修改這些函數(shù),使它們返回超類中的某個(新增)字段,然后銷毀子類。

第九章 簡化條件表達式

  1. Decompose Conditional(分解條件表達式)
    • 你有一個復(fù)雜的條件(if-then-else)語句。從if、then、else三個段落中分別提煉獨立函數(shù)。
  2. Consolidate Conditional Expression(合并條件表達式)
    • 你有一系列條件測試,都得到相同結(jié)果。將這些測試合并為一個條件表達式,并將這個條件表達式提煉成為一個獨立函數(shù)。
  3. Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片段)
    • 在條件表達式的每個分支上有著相同的一段代碼。將這段重復(fù)代碼搬移到條件表達式之外。
  4. Remove Control Flag(移除控制標記)
    • 在一系列布爾表達式中,某個變量帶有“控制標記”(control flag)的作用。以break語句或return語句取代控制標記。
  5. Replace Nested Conditional with Guard Clauses(以衛(wèi)語句取代嵌套條件表達式)
    • 函數(shù)中的條件邏輯使人難以看清正常的執(zhí)行路徑。使用衛(wèi)語句表現(xiàn)所有特殊情況。
  6. Replace Conditional with Polymorphism(以多態(tài)取代條件表達式)
    • 你手上有個條件表達式,它根據(jù)對象類型的不同而選擇不同的行為。將這個條件表達式的每個分支放進一個子類內(nèi)的覆寫函數(shù)中,然后將原始函數(shù)聲明為抽象函數(shù)。
  7. Introduce Null Object(引入Null對象)
    • 你需要再三檢查對象是否為null。將null值替換為null對象。
  8. Introduce Assertion(引入斷言)
    • 某一段代碼需要對程序狀態(tài)做出某種假設(shè)。以斷言明確表現(xiàn)這種假設(shè)。

第十章 簡化函數(shù)調(diào)用

  1. Rename Method(函數(shù)改名)
    • 函數(shù)的名稱未能揭示函數(shù)的用途。修改函數(shù)名稱。
  2. Add Parameter(添加參數(shù))
    • 某個函數(shù)需要從調(diào)用端得到更多信息。為此函數(shù)添加一個對象參數(shù),讓該對象帶進函數(shù)所需信息。
  3. Remove Parameter(移除函數(shù))
    • 函數(shù)本體不再需要某個參數(shù)。將該參數(shù)去除。
  4. Separate Query fom Modifier(將查詢函數(shù)和修改函數(shù)分離)
    • 某個函數(shù)即返回對象狀態(tài)值,又修改對象狀態(tài)。建立兩個不同的函數(shù),其中一個負責查詢,另一個負責修改。
  5. Parameterize Method(令函數(shù)攜帶參數(shù))
    • 若干函數(shù)做了類似的工作,但在函數(shù)本體中卻包含了不同的值。
  6. Replace Parameter with Explicit Methods(以明確函數(shù)取代參數(shù))
    • 你有一個函數(shù),其中完全取決于參數(shù)值而采取不同行為。針對該參數(shù)的每一個可能值,建立一個獨立函數(shù)。
  7. Preserve Whole Object(保持對象完整)
    • 你從某個對象中取出若干值,將他們作為某一次函數(shù)調(diào)用時的參數(shù)。改為傳遞整個對象。
  8. Replace Parameter with Methods(以函數(shù)取代參數(shù))
    • 對象調(diào)用某個函數(shù),并將所得結(jié)果作為參數(shù),傳遞給另一個函數(shù)。而接受該參數(shù)的函數(shù)本身也能夠調(diào)用前一個函數(shù)。讓參數(shù)接受者去除該項參數(shù),并直接調(diào)用前一個函數(shù)。
  9. Introduce Parameter Object(引入?yún)?shù)對象)
    • 某些參數(shù)總是很自然地同時出現(xiàn)。以一個對象取代這些參數(shù)。
  10. Remove Setting Method(移除設(shè)置函數(shù))
    • 類中的某個字段應(yīng)該在對象創(chuàng)建時被設(shè)值,然后就不再改變。去掉該字段的所有設(shè)值函數(shù)。
  11. Hide Method(隱藏函數(shù))
    • 有一個函數(shù),從來沒有被其他任何類用到。將這個函數(shù)修改為private。
  12. Replace Constructor with Factory Method(以工廠函數(shù)取代構(gòu)造函數(shù))
    • 你希望在創(chuàng)建對象時不僅僅是做簡單的構(gòu)建動作。將構(gòu)造函數(shù)替換為工廠函數(shù)。
  13. Encapsulate Downcase(封裝向下轉(zhuǎn)型)
    • 某個函數(shù)返回的對象,需要由函數(shù)調(diào)用者執(zhí)行向下轉(zhuǎn)型(downcase)。將向下轉(zhuǎn)型動作移到函數(shù)中。
  14. Replace Error Code with Exception(以異常取代錯誤碼)
    • 某個函數(shù)返回一個特定的代碼,用以表示某種錯誤情況。改用異常。
  15. Replace Exception with Test(以測試取代異常)
    • 面對一個調(diào)用者可以預(yù)見檢查的條件,你拋出了一個異常。修改調(diào)用者,使它在調(diào)用函數(shù)之前先做檢查。

第十一章 處理概括關(guān)系

  1. Pull Up Field(字段上移)
    • 兩個子類擁有相同的字段。將該字段移至超類。
  2. Pull Up Method(函數(shù)上移)
    • 有些函數(shù),在各個子類中產(chǎn)生完全相同的結(jié)果。將該函數(shù)移至超類。
  3. Pull Up Contrructor Body(構(gòu)造函數(shù)本體上移)
    • 你在各個子類中擁有一些構(gòu)造函數(shù),它們的本體幾乎完全一致。在超類中新建一個構(gòu)造函數(shù),并在子類構(gòu)造函數(shù)中調(diào)用它。
  4. Push Down Method(函數(shù)下移)
    • 超類中的某個函數(shù)只與部分(而非全部)子類有關(guān)。將這個函數(shù)移到相關(guān)的那些子類去。
  5. Push Down Field(字段下移)
    • 超類中的某個字段只被部分(而非全部)子類用到。將這個字段移到需要它的那些子類去。
  6. Extract Subclass(提煉子類)
    • 類中的某些特性只被某些(而非全部)實例用到。新建一個子類,將上面所說的那一部分特性移到子類中。
  7. Extract Superclass(提煉超類)
    • 兩個類有相似特性。為兩個類建立一個超類,將相同特性移至超類。
  8. Extract Interface(提煉接口)
    • 若干客戶使用類接口中的同一子集,或者兩個類的接口有部分相同。將相同的子集提煉到一個獨立接口中。
  9. Collapse Hierarchy(折疊繼承體系)
    • 超類和子類之間無太大區(qū)別。將他們合為一體。
  10. Form TemPlate Method(塑造模板函數(shù))
    • 你有一些子類,其中相應(yīng)的某些函數(shù)以相同順序執(zhí)行類似的操作,但各個操作的細節(jié)上有所不同。將這些操作分別放進獨立函數(shù)中,并保持它們都有相同簽名,于是原函數(shù)也就變得相同了。然后將原函數(shù)上移至超類。
  11. Replace Inheritance with Delegation(以委托取代繼承)
    • 某個子類只使用超類接口中德一部分,或是根本不需要繼承而來的數(shù)據(jù)。在子類中新建一個字段用以保存超類;調(diào)整子類函數(shù),令它改而委托超類;然后去掉兩者之間的繼承關(guān)系。
  12. Replace Delegation with Inheritance(以繼承取代委托)
    • 你在兩個類之間使用委托關(guān)系,并經(jīng)常為整個接口編寫許多極簡單的委托函數(shù)。讓委托類繼承受托類。

第十二章 大型重構(gòu)

  1. Tease Apart Inheritance(梳理并分解繼承體系)
    • 某個繼承體系同時承擔兩項責任。建立兩個繼承體系,并通過委托關(guān)系讓其中一個可以調(diào)用另外一個。
  2. Convert Procedural Design to Objects(將過程化設(shè)計轉(zhuǎn)化為對象設(shè)計)
    • 你手上有一些傳統(tǒng)過程化風格的代碼。將數(shù)據(jù)記錄變成對象,將大塊的行為分成小塊,并將行為移入相關(guān)對象之中。
  3. Separate Domain from Presentation(將領(lǐng)域和表述/顯示分離)
    • 某些GUI類之中包含了領(lǐng)域邏輯。將領(lǐng)域邏輯分離出來,為他們建立獨立的領(lǐng)域類。
  4. Extract Hierarchy(提煉繼承體系)
    • 你有某個類做了太多工作,其中一部分工作時以大量條件表達式完成的。建立繼承體系,以一個類表示一種特殊情況。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容