Java, Only Java!

          統(tǒng)計(jì)

          留言簿(20)

          積分與排名

          好友空間

          文檔技巧

          閱讀排行榜

          評(píng)論排行榜

          《重構(gòu)》的讀書筆記–方法列表

        1. 第5章 重構(gòu)列表
        2. 第6章 重新組織函數(shù)
        3. 第8章 重新組織數(shù)據(jù)
        4. 第9章 簡(jiǎn)化條件表達(dá)式 237
        5. 第10章 簡(jiǎn)化函數(shù)調(diào)用
        6. 第11章 處理概括關(guān)系 319

            第5章 重構(gòu)列表

            5.1 重構(gòu)的記錄格式103

            這個(gè)格式可以作為自己未來(lái)記錄重構(gòu)手法的標(biāo)準(zhǔn),方便查閱自己常用的和總結(jié)的重構(gòu)方式:

            • 名稱:重構(gòu)詞匯表
            • 概要:適用的情景,以及所做的事情
            • 動(dòng)機(jī):說(shuō)明“為什么需要”和“什么情況不做”
            • 做法:重構(gòu)的步驟(看似簡(jiǎn)單,其實(shí)很重要,因?yàn)橹貥?gòu)不建議跳躍完成,最好保證每次一小步都是正確的)
            • 范例:通過(guò)例子正確的理解重構(gòu)手法的操作方式

            5.2 尋找引用點(diǎn)105

            引用點(diǎn):就是那些被重構(gòu)的代碼被哪些代碼調(diào)用了。現(xiàn)在的重構(gòu)工具已經(jīng)可以簡(jiǎn)化這些操作,但是工具永遠(yuǎn)都是有限的,除了工具還應(yīng)該熟悉一些基本的操作手段。

            5.3 這些重構(gòu)手法有多成熟106

            學(xué)習(xí)和使用這些重構(gòu)僅僅是個(gè)起點(diǎn),業(yè)務(wù)在變、工具在變、語(yǔ)言在變、對(duì)事物的理解也在變,因此完全挺有自己的重構(gòu)手段才是最終的目標(biāo)。

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

            • Extract Method是本章的重點(diǎn),用于解決Long Methods問(wèn)題;
            • Extract Method的困難是處理局部變量,特別是局部變量中的臨時(shí)變量,為此需要本章中的其他方法作為補(bǔ)充。

            6.1 (P110)Extract Method(提煉函數(shù))

            動(dòng)機(jī):Long Methods問(wèn)題或者代碼需要Comments問(wèn)題;
            方法:(可以使用IDE提供的重構(gòu)工具,下面的具體操作的原理)

            • 創(chuàng)造一個(gè)新函數(shù),根據(jù)這個(gè)函數(shù)的意圖來(lái)對(duì)它命名;
            • 將提煉的代碼拷貝到新建函數(shù)中;
            • 檢查提煉的代碼是否引用了“作用域限于原函數(shù)”的變量(局部變量、原函數(shù)參數(shù))
            • 檢查提煉的代碼是否包含了“僅用于被提煉代碼段”的臨時(shí)變量
              • 如果有,在目標(biāo)函數(shù)中將之聲明為局部變量
            • 檢查被提煉代碼段,看看是否有任何局部變量的值被他改變,
              • 如果臨時(shí)變量的值被修改了,嘗試將提煉的代碼變?yōu)橐粋€(gè)查詢,將結(jié)果返回給相關(guān)變量;
              • 如果不好操作,或者被修改的變量多于一個(gè),可以嘗試(分解臨時(shí)變量/以查詢替換變量)等手段了。
            • 將被提煉代碼段中需要被讀取的局部變量,當(dāng)參數(shù)傳給目標(biāo)函數(shù)
            • 處理完所有局部變量后,編譯,檢查
            • 在源函數(shù)中,將被提煉的代碼替換為對(duì)目標(biāo)函數(shù)的調(diào)用
            • 編譯,檢查,測(cè)試

            6.2 Inline Method(內(nèi)聯(lián)函數(shù))117

            動(dòng)機(jī):當(dāng)函數(shù)內(nèi)部的代碼與其名稱一樣易懂,可以在函數(shù)調(diào)用點(diǎn)插入函數(shù)本體,移除該函數(shù)。
            補(bǔ)充:對(duì)有一群不太合理的函數(shù),可以先內(nèi)聯(lián)為一個(gè)長(zhǎng)函數(shù),然后再提煉出合理的小函數(shù)

            6.3 Inline Temp(內(nèi)聯(lián)臨時(shí)變量)119

            動(dòng)機(jī):當(dāng)臨時(shí)變量只被一個(gè)簡(jiǎn)單的表達(dá)式賦值一次,而且它妨礙其他重構(gòu)方法時(shí),才需要重構(gòu)
            條件:Inline Temp多半是為Replace Temp with Query(以查詢?nèi)〈R時(shí)變量)準(zhǔn)備
            方法:將所有對(duì)該變量的引用動(dòng)作替代成對(duì)它賦值的表達(dá)式本身。

            6.4 Replace Temp with Query(以查詢?nèi)〈R時(shí)變量)120

            動(dòng)機(jī):你的程序以一個(gè)臨時(shí)變量保存一個(gè)表達(dá)式的計(jì)算結(jié)果
            方法:將表達(dá)式提煉出獨(dú)立的函數(shù),然后臨時(shí)變量的調(diào)用替換成新函數(shù)的調(diào)用。此后新函數(shù)也能被調(diào)用。
            具體方法: 將提煉出來(lái)的函數(shù)用private修飾,如果獨(dú)立函數(shù)有副作用,那對(duì)它進(jìn)行Separate Query from Modifier(將查詢函數(shù)和修改函數(shù)分離)

            6.5 Introduce Explaining Variable(引入解釋性變量)124

            將復(fù)雜表達(dá)式(或者其中一部分)的結(jié)果賦值給一個(gè)臨時(shí)變量,用臨時(shí)變量名稱來(lái)解釋表達(dá)式的用途

            6.6 Split Temporary Variable(分解臨時(shí)變量)128

            臨時(shí)變量被賦值超過(guò)一次,但是它既不是循環(huán)變量也不是被用于收集計(jì)算結(jié)果
            原因:一個(gè)變量應(yīng)該承擔(dān)一個(gè)責(zé)任,如果被賦值多次很可能承擔(dān)了多個(gè)責(zé)任
            方法:針對(duì)每次賦值,創(chuàng)建新的臨時(shí)變量

            6.7 Remove Assignments to Parameters(移除對(duì)參數(shù)的賦值)131

            java是值傳遞,對(duì)參數(shù)的任何修改都不會(huì)對(duì)調(diào)用端產(chǎn)生影響,所以對(duì)于用過(guò)引用傳遞的人可能會(huì)發(fā)生理解錯(cuò)誤
            參數(shù)應(yīng)該僅表示“被傳遞過(guò)來(lái)的東西”

            6.8 Replace Method with Method Object(以函數(shù)對(duì)象取代函數(shù))135

            動(dòng)機(jī):在大型函數(shù)內(nèi),對(duì)局部變量的使用導(dǎo)致難以使用Extract Method(提煉函數(shù))進(jìn)行重構(gòu)
            方法:將這個(gè)函數(shù)放入一個(gè)對(duì)象里,局部變量變成對(duì)象成員變量,然后可以在同一對(duì)象中將這個(gè)大型函數(shù)分解為多個(gè)小型函數(shù)。
            原因:局部變量會(huì)增加分解函數(shù)的困難度

            6.9 Substitute Algorithm(替換算法)139

            把某個(gè)算法替換成更清晰的方法(算法)。

            第7章 在對(duì)象之間搬移特性141

            本章的重點(diǎn)是搬移(Move)。“決定把責(zé)任放在哪里”是面向?qū)ο笤O(shè)計(jì)中最重要的事情之一,但是剛開(kāi)始設(shè)計(jì)時(shí),由于技術(shù)和業(yè)務(wù)知識(shí)的不足無(wú)法保證做出的決定是正確的,那么后期調(diào)整中將“責(zé)任”搬移到正確的對(duì)象中就是重要的重構(gòu)手段。而Move Method(142)和Move Field(146)就是搬移“責(zé)任”過(guò)程中最基本的兩個(gè)方法。

            7.1 Move Method(搬移函數(shù))142

            動(dòng)機(jī):類中某個(gè)函數(shù)與其他類交互過(guò)多
            方法:將該函數(shù)搬移到交互最多的類里面,將舊函數(shù)變成委托函數(shù)或者刪除。
            具體方法:

            • 檢查源類中被源函數(shù)使用的一切特性,如果特性被其他函數(shù)使用,考慮這些函數(shù)一起搬移
            • 檢查源類的子類和超類,看看是否有該函數(shù)的聲明,如果出現(xiàn),很可能不能搬移。
            • 目標(biāo)類需要使用源類的特性:
              1. 將該特性轉(zhuǎn)移到目標(biāo)類;
              2. 建立目標(biāo)類到源類之間引用。
              3. 將源類作為參數(shù)傳給目標(biāo)類
              4. 將該特性作為參數(shù)傳給目標(biāo)類
            • 如果源函數(shù)包含異常處理,需要考慮是在目標(biāo)類還是源函數(shù)處理

            7.2 Move Field(搬移字段)146

            動(dòng)機(jī):類中某個(gè)字段被其他類頻繁使用(包括:傳參數(shù)、調(diào)用取值函數(shù)、調(diào)用設(shè)值函數(shù))
            方法:將該字段搬移到目標(biāo)類
            具體方法:

            • 先封裝這個(gè)字段;
            • 在目標(biāo)類建立這個(gè)字段,并且封裝;
            • 設(shè)定目標(biāo)對(duì)象;
            • 替換對(duì)源字段的引用為目標(biāo)類的取值函數(shù)

            7.3 Extract Class(提煉類)149

            動(dòng)機(jī):一個(gè)類做了兩個(gè)類的事
            方法:

            • 建立新類,將相應(yīng)的字段和函數(shù)放到新類
            • 使用Move Field重構(gòu);
            • 使用Move Method重構(gòu);
            • 判斷是否需要公開(kāi)新類。

            7.4 Inline Class(將類內(nèi)聯(lián)化)154

            動(dòng)機(jī):某個(gè)類功能太少,與Extract Class(提煉類)相反 方法:將這個(gè)類的所有特性搬移到另一類中,移除該類。
            原因:多次Extract Class后,原類大部分功能被移走,將這個(gè)萎縮類與其他相近的類合并

            7.5 Hide Delegate(隱藏“委托關(guān)系”)157

            動(dòng)機(jī):客戶端通過(guò)委托類來(lái)取得另一個(gè)對(duì)象的信息
            方法:在服務(wù)類上建立客戶端所需數(shù)據(jù)的函數(shù),然后隱藏委托關(guān)系
            依據(jù):符合“封裝”的特性。當(dāng)委托類發(fā)生變化不會(huì)對(duì)客戶端造成影響,減少客戶端與調(diào)用者之間的耦合性。

            7.6 Remove Middle Man(移除中間人)160

            動(dòng)機(jī):某個(gè)類做了過(guò)多的委托動(dòng)作
            方法:讓客戶端直接調(diào)用委托類,與Hide Delegate(隱藏“委托關(guān)系”)相反 依據(jù):當(dāng)原委托類的特性越來(lái)越多,服務(wù)類的委托函數(shù)將越來(lái)越長(zhǎng),需要讓客戶端直接調(diào)用,避免服務(wù)類淪為中間人。

            7.7 Introduce Foreign Method(引入外加函數(shù))162

            動(dòng)機(jī):使用的類無(wú)法提供某個(gè)功能,但是又不能修改該類
            方法:新建函數(shù),并將服務(wù)類的對(duì)象實(shí)例作為參數(shù)傳入。
            具體動(dòng)機(jī):如果需要為服務(wù)類增加大量的方法,請(qǐng)考慮使用Introduce Local Extension(引入本地?cái)U(kuò)展)

            7.8 Introduce Local Extension(引入本地?cái)U(kuò)展)164

            動(dòng)機(jī):使用的類無(wú)法提供多個(gè)功能,但是又不能修改該類
            方法:建立新的類,在新類中建立需要的功能函數(shù),可以作為服務(wù)類的子類實(shí)現(xiàn)新的類,也可以包裝服務(wù)類實(shí)現(xiàn)新的類。
            具體情況:

            • 首選子類,工作量最小
              • 但是必須在對(duì)象創(chuàng)建期實(shí)施,如果不行就只能選擇包裝類;
              • 子類的對(duì)象不能修改父類的數(shù)據(jù),否則建議選擇包裝類,因?yàn)闀?huì)導(dǎo)致父類對(duì)象與子類對(duì)象的數(shù)據(jù)可能不一致
            • 包裝類需要實(shí)現(xiàn)被包裝對(duì)象的所有接口,工作量很大。

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

            本章重點(diǎn)是如何更好地封裝各種類型的數(shù)據(jù)。最常用的手段就是Self Encapsulate Field(171)

            8.1 Self Encapsulate Field(自封裝字段)171

            動(dòng)機(jī):直接訪問(wèn)一個(gè)字段,但是字段之間的耦合關(guān)系逐漸變得笨拙。
            方法:自封裝就是在對(duì)于類內(nèi)部的字段也封裝一個(gè)設(shè)值取值的函數(shù)。
            爭(zhēng)論:字段訪問(wèn)方式是直接訪問(wèn)還是間接訪問(wèn)一致?tīng)?zhēng)論不斷
            間接訪問(wèn)的好處:

            • 子類可以通過(guò)覆蓋一個(gè)函數(shù)來(lái)改變獲取數(shù)據(jù)的途徑;
            • 支持更靈活的數(shù)據(jù)管理,如延遲加載(需要用到才加載)等。直接訪問(wèn)的好處:代碼容易讀懂,理解不需要轉(zhuǎn)換為取值函數(shù)。

            8.2 Replace Data Value with Object(以對(duì)象取代數(shù)據(jù)值)175

            動(dòng)機(jī):假如一個(gè)數(shù)據(jù)項(xiàng)需要與其他數(shù)據(jù)一起使用才有意義。數(shù)據(jù)已經(jīng)不僅僅由一條簡(jiǎn)單的數(shù)據(jù)項(xiàng)組成,例如:電話號(hào)碼
            方法:將數(shù)據(jù)變成對(duì)象。

            8.3 Change Value to Reference(將值對(duì)象改為引用對(duì)象)179

            動(dòng)機(jī):一個(gè)類有許多相等的實(shí)例,希望把這些相等的實(shí)例統(tǒng)一為一個(gè)對(duì)象,方便統(tǒng)一修改或者進(jìn)行相等性比較
            方法:將值對(duì)象變成引用對(duì)象
            “引用對(duì)象”與“值對(duì)象”的區(qū)別:

            • 每個(gè)引用對(duì)象代表著現(xiàn)實(shí)中一個(gè)對(duì)象,使用對(duì)象的一致性用來(lái)檢測(cè)兩個(gè)對(duì)象是否相等,即(==)
            • 值對(duì)象完全由其自身的值來(lái)相互區(qū)分,需要重寫一些方法用來(lái)檢測(cè)兩個(gè)對(duì)象是否相等。(重寫equals()和hashcode()方法)具體方法:
            • 需要使用工廠模式來(lái)創(chuàng)建對(duì)象
            • 需要另一個(gè)對(duì)象(或者是自身)作為訪問(wèn)點(diǎn)來(lái)訪問(wèn)定義的引用對(duì)象,對(duì)象用Dictionary或者HashTable來(lái)保存對(duì)象
            • 決定對(duì)象是預(yù)先創(chuàng)建還是動(dòng)態(tài)創(chuàng)建

            8.4 Change Reference to Value(將引用對(duì)象改為值對(duì)象)183

            動(dòng)機(jī):引用對(duì)象,很小且不可變,而且不易管理

            • 很小:創(chuàng)建許多也不會(huì)消耗太多內(nèi)存
            • 不可變:不需要復(fù)雜的管理代碼,也不需要考慮同步問(wèn)題,還會(huì)造成別名問(wèn)題具體方法:
            • 檢查重構(gòu)目標(biāo)是否是不可變對(duì)象或者可修改成不可變對(duì)象
              • 使用Remove Setting Method變成不可變對(duì)象
              • 如果無(wú)法修改成不可變對(duì)象,就放棄重構(gòu)
            • 重寫hashCode和equals()方法
            • 取消使用的工廠模式,并將對(duì)象的構(gòu)造函數(shù)設(shè)為public

            8.5 Replace Array with Object(以對(duì)象取代數(shù)組)186

            動(dòng)機(jī):如果數(shù)據(jù)存儲(chǔ)的值代表不同的東西。
            方法:將數(shù)組變成對(duì)象,數(shù)組的每個(gè)元素用字段表示

            8.6 Duplicate Observed Data(復(fù)制“被監(jiān)視數(shù)據(jù)”)189

            動(dòng)機(jī): 有業(yè)務(wù)數(shù)據(jù)置身于GUI控件中,而與業(yè)務(wù)相關(guān)的函數(shù)需要訪問(wèn)這些數(shù)據(jù)
            方法:將業(yè)務(wù)數(shù)據(jù)復(fù)制到業(yè)務(wù)類中。建立Observer模式,同步UI和業(yè)務(wù)類的數(shù)據(jù)。

            8.7 Change Unidirectional Association to Bidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))197

            動(dòng)機(jī):兩個(gè)類相互之間都需要對(duì)方的數(shù)據(jù),但是相互之間只有一條單向的連接
            這個(gè)重構(gòu)需要添加測(cè)試,因?yàn)椤胺聪蛑羔槨焙苋菀自斐苫靵y。
            具體方法:

            • 在被引用類添加字段,保存引用類的指針;
            • 判斷由哪個(gè)類來(lái)控制關(guān)聯(lián)關(guān)系;
              • 如果兩者都是引用對(duì)象,且關(guān)聯(lián)關(guān)系為“一對(duì)多”的關(guān)系,那么就由“擁有單一引用”的對(duì)象作為控制者;
              • 如果A對(duì)象是B對(duì)象的部件,則由B對(duì)象負(fù)責(zé)控制關(guān)系;
              • 如果兩者都是引用對(duì)象,且關(guān)聯(lián)關(guān)系為“多對(duì)多”的關(guān)系,那么隨意確定一個(gè)對(duì)象作為控制者。
            • 在被控端建立輔助函數(shù),命名清晰地描述其用途;
              • 如果修改函數(shù)在控制端,則由其負(fù)責(zé)更新反向指針;
              • 如果修改函數(shù)在被控制端,則在控制端建立一個(gè)修改反射指針的函數(shù),由修改函數(shù)調(diào)用其修改反向指針。
              • 兩者是一對(duì)多關(guān)系,有單一引用承擔(dān)控制關(guān)聯(lián)關(guān)系責(zé)任

            8.8 Change Bidirectional Association to Unidirectional(將雙向關(guān)聯(lián)改為單向關(guān)聯(lián))200

            動(dòng)機(jī):兩個(gè)類有雙向關(guān)聯(lián),但是一個(gè)類不再需要另一個(gè)類的特性
            原因:

            • 雙向關(guān)聯(lián)可能造成僵尸對(duì)象,不能被清除釋放內(nèi)存。
            • 使兩個(gè)類存在耦合關(guān)系,一個(gè)類的變化會(huì)導(dǎo)致另一類的變化。方法:去除雙向關(guān)聯(lián)
              困難:檢查可行性

            8.9 Replace Magic Number with Symbolic Constant(以字面常量取代魔法數(shù))204

            動(dòng)機(jī):有一個(gè)字面常量(除了0和1之外)
            方法:創(chuàng)建常量賦值以該字面常量,給予命名。

            8.10 Encapsulate Field(封裝字段)206

            動(dòng)機(jī):一個(gè)類有public字段
            將它聲明為private,并提供相應(yīng)的訪問(wèn)函數(shù)

            8.11 Encapsulate Collection(封裝集合)208

            動(dòng)機(jī):類中使用集合,但是集合不能提供給用戶直接操作,而是提供函數(shù)操作集合,降低用戶與集合之間的耦合度
            方法:提供函數(shù)返回集合的只讀副本,并提供增加和刪除集合元素的函數(shù)
            具體方法:

            • Java2:封裝Set
            • Java1.1:封裝Vector
            • 封裝數(shù)組

            8.12 Replace Record with Data Class(以數(shù)據(jù)類取代記錄)217

            動(dòng)機(jī):面對(duì)舊程序中Record數(shù)據(jù)結(jié)構(gòu),新建類取代它
            方法:為該記錄創(chuàng)建一個(gè)“啞”數(shù)據(jù)對(duì)象。

            Type Code(類型碼)

            常見(jiàn)于過(guò)去的C語(yǔ)言編程中,因?yàn)闆](méi)有枚舉,所以采用類型碼的方式標(biāo)注。這個(gè)重構(gòu)遇到的機(jī)會(huì)比較小

            8.13 Replace Type Code with Class(以類取代類型碼)218

            動(dòng)機(jī):類中的數(shù)值類型碼不影響類的行為
            方法:以一個(gè)新類替代類型碼

            8.14 Replace Type Code with Subclasses(以子類取代類型碼)223

            動(dòng)機(jī):有一個(gè)不可變的類型碼且影響類的行為
            標(biāo)志:switch或者if-then-else類的條件表達(dá)式,這個(gè)重構(gòu)是Replace Conditional with Polymorphism的準(zhǔn)備工具
            方法:以子類取代這個(gè)類型碼

            8.15 Replace Type Code with State/Strategy(以State/Strategy取代類型碼)227

            動(dòng)機(jī):有一個(gè)類型碼且影響類的行為,但是無(wú)法通過(guò)繼承消除(類型碼可變化)
            方法:以狀態(tài)對(duì)象取代。

            8.16 Replace Subclass with Fields(以字段取代子類)232

            動(dòng)機(jī):各個(gè)子類唯一區(qū)別只在“返回常量的數(shù)據(jù)”的函數(shù)上
            方法:修改這些函數(shù)使它們返回超類的某個(gè)(新增)字段,然后銷毀子類。

            第9章 簡(jiǎn)化條件表達(dá)式 237

            條件邏輯非常復(fù)雜,也非常難以理解,通過(guò)重構(gòu)將復(fù)雜的邏輯展現(xiàn)為簡(jiǎn)單的邏輯塊。
            有些重構(gòu)方法看起來(lái)非常簡(jiǎn)單,因?yàn)橹貥?gòu)最重要的思想不是方法有多精妙,而是傳達(dá)了一個(gè)小步快走的理念。就是一次只完成一個(gè)小重構(gòu),然后測(cè)試確保沒(méi)有錯(cuò)誤。然后,再進(jìn)行下一個(gè)小重構(gòu)和測(cè)試。從而整個(gè)大重構(gòu)通過(guò)多個(gè)簡(jiǎn)單的小重構(gòu)完成,避免大重構(gòu)出錯(cuò)后需要全部回滾的問(wèn)題。

            9.1 Decompose Conditional(分解條件表達(dá)式)238

            動(dòng)機(jī):if-then-else語(yǔ)句,不同分支做不同事動(dòng)機(jī)成大型函數(shù),本身就難以閱讀,尤其在帶有復(fù)雜條件的邏輯中。方法:

            • 將if語(yǔ)句提煉為函數(shù)
            • 將then和else段落提煉為函數(shù)
            • 對(duì)于存在嵌套的條件邏輯,先判斷是否可以用Replace Nested Conditional with Guard Clauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)消除。不行再分解每個(gè)條件

            9.2 Consolidate Conditional Expression(合并條件表達(dá)式)240

            動(dòng)機(jī):有一系列條件判斷都服務(wù)于共同的目標(biāo)
            方法:將這些條件判斷合并為同一個(gè)表達(dá)式,再將這個(gè)表達(dá)式提煉為獨(dú)立函數(shù)
            原因:

            • 只是一次條件檢查,只是存在多個(gè)并列條件需要檢查而已
            • 為Extract Method(提煉函數(shù))做準(zhǔn)備,通過(guò)函數(shù)名告知“為什么這么做”

            9.3 Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片段)243

            動(dòng)機(jī):在條件表達(dá)式的不同分支中存在相同的代碼
            方法:將這些重復(fù)代碼搬移到條件表達(dá)式之外,多行代碼還可以再提煉為獨(dú)立函數(shù)。
            例如:當(dāng)try和catch執(zhí)行相同代碼,可以將代碼移到final區(qū)段。

            9.4 Remove Control Flag(移除控制標(biāo)記)245

            動(dòng)機(jī):在循環(huán)執(zhí)行的程序段中,某個(gè)變量定義為判斷條件中的控制標(biāo)記(control flag),增加了代碼理解的復(fù)雜度
            方法:

            • 以break或者continue代替;
            • 也可以通過(guò)函數(shù)調(diào)用和return語(yǔ)句來(lái)實(shí)現(xiàn)。

            9.5 Replace Nested Conditional with Guard Clauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)250

            衛(wèi)語(yǔ)句:如果某個(gè)條件極其罕見(jiàn),就應(yīng)該單獨(dú)檢查該條件,并在該條件為真時(shí)立刻從函數(shù)中返回,這樣的單獨(dú)檢查被稱為“衛(wèi)語(yǔ)句”(guard clauses)
            動(dòng)機(jī):函數(shù)中的條件邏輯使人難以看清正確的執(zhí)行路徑。
            方法:使用衛(wèi)語(yǔ)句表現(xiàn)所有的特殊情況

            9.6 Replace Conditional with Polymorphism(以多態(tài)取代條件表達(dá)式)255

            動(dòng)機(jī):存在條件表達(dá)式根據(jù)對(duì)象的類型不同選擇不同的行為
            方法:將表達(dá)式分支放進(jìn)不同子類,然后重寫方法,將原始函數(shù)提煉為抽象函數(shù)。

            9.7 Introduce Null Object(引入Null對(duì)象)260

            動(dòng)機(jī):需要再三檢查對(duì)象是否為null
            方法:將null值替代為null對(duì)象,如果原始類不允許修改可以使用Null接口來(lái)檢查“對(duì)象是否為Null”。

            9.8 Introduce Assertion(引入斷言)267

            動(dòng)機(jī):某段代碼需要對(duì)程序狀態(tài)顯式地表明某種假設(shè)
            方法:以斷言明確表現(xiàn)這種假設(shè)
            具體方法: 斷言在 發(fā)布的時(shí)候統(tǒng)統(tǒng) 被跳過(guò)

            第10章 簡(jiǎn)化函數(shù)調(diào)用

            使接口變得更加簡(jiǎn)潔易用的重構(gòu)方法。

            • 修改函數(shù)名稱,使之容易理解;
            • 縮短參數(shù)列表;
            • 不同的功能分離到不同的函數(shù)中;
            • 隱藏函數(shù),提升接口的質(zhì)量。

            10.1 Rename Method(函數(shù)改名)273

            動(dòng)機(jī):函數(shù)的名稱不能說(shuō)明函數(shù)的用途
            方法:將舊函數(shù)代碼搬移到新函數(shù),舊函數(shù)跳轉(zhuǎn)到新函數(shù)。

            10.2 Add Parameter(添加參數(shù))275

            動(dòng)機(jī):被調(diào)用的函數(shù)需要從調(diào)用函數(shù)中得到更多的信息
            方法:為被調(diào)用的函數(shù)添加參數(shù)
            抉擇:

            • 現(xiàn)有參數(shù)是否提供足夠的信息?
            • 這個(gè)函數(shù)是否應(yīng)該移動(dòng)到擁有該信息的對(duì)象中?
            • 加入新參數(shù)是否合適?
            • 如果需要的參數(shù)過(guò)多,是否需要使用Introduce Parameter Object(引入?yún)?shù)對(duì)象)?

            10.3 Remove Parameter(移除參數(shù))277

            動(dòng)機(jī):函數(shù)不需要某個(gè)參數(shù)(不需要了就放棄,保留也需要付出代價(jià))
            方法:

            • 如果是獨(dú)立的函數(shù),直接將該參數(shù)移除
            • 如果是多態(tài)函數(shù),不能移除,就增加一個(gè)新的沒(méi)有這個(gè)參數(shù)的函數(shù),使調(diào)用者的工作得到簡(jiǎn)化

            10.4 Separate Query from Modifier(將查詢函數(shù)和修改函數(shù)分離)279

            動(dòng)機(jī):某個(gè)函數(shù)既修改對(duì)象狀態(tài),又返回對(duì)象狀態(tài)值。(使調(diào)用者擔(dān)心誤操作修改了不應(yīng)該修改的數(shù)據(jù),增加調(diào)用者的操作負(fù)擔(dān))
            本質(zhì):函數(shù)功能簡(jiǎn)潔、明確,如果一個(gè)函數(shù)具備多個(gè)功能,就把它們分離成多個(gè)函數(shù)。
            方法:建立兩個(gè)不同的函數(shù),其中一個(gè)負(fù)責(zé)查詢,另一個(gè)負(fù)責(zé)修改。
            原則:

            • 任何一個(gè)有返回值的函數(shù)都不應(yīng)該有看得到的副作用。
            • 編碼中主要考慮的不是代碼的效率,而是代碼的易讀性,效率可以在未來(lái)上線的時(shí)候再根據(jù)實(shí)際需要調(diào)整。多線程:將修改和查詢函數(shù)封裝在一個(gè)同步函數(shù)中分開(kāi)調(diào)用。

            10.5 Parameterize Method(令函數(shù)攜帶參數(shù))283

            動(dòng)機(jī):幾個(gè)函數(shù),做了類似的工作,只是代碼中的系數(shù)不同
            方法:建立單一函數(shù),以參數(shù)作為系數(shù)

            10.6 Replace Parameter with Explicit Methods(以明確函數(shù)取代參數(shù))285

            動(dòng)機(jī):函數(shù)依賴于參數(shù)值的不同而采取不同的行為
            方法:針對(duì)該參數(shù)的每個(gè)可能值,建立獨(dú)立函數(shù)。
            對(duì)比:與Parameterize Method(令函數(shù)攜帶參數(shù))相反,但是目的都是把復(fù)雜的邏輯判斷消除 目的:提供清晰的入口。
            如果參數(shù)值對(duì)函數(shù)行為影響不大,不應(yīng)該采用此方法。

            10.7 Preserve Whole Object(保持對(duì)象完整)288

            動(dòng)機(jī):從某個(gè)對(duì)象取若干個(gè)值,把他們作為參數(shù)傳給函數(shù)
            方法:改為調(diào)用整個(gè)對(duì)象
            目的:避免過(guò)長(zhǎng)參數(shù)列表
            缺陷:如果傳遞的是值,那么函數(shù)只依賴那些值;如果傳遞的是對(duì)象,函數(shù)則依賴對(duì)象,會(huì)導(dǎo)致耦合
            注意:有時(shí)候函數(shù)使用了很多來(lái)自某個(gè)對(duì)象的數(shù)據(jù),那么應(yīng)該考慮使用(Move Method)將這個(gè)函數(shù)移到關(guān)系密切的對(duì)象中

            10.8 Replace Parameter with Methods(以函數(shù)取代參數(shù))292

            動(dòng)機(jī):對(duì)象調(diào)用某個(gè)函數(shù),并將所得結(jié)果作為參數(shù)傳遞給另一個(gè)函數(shù),而接受該參數(shù)的函數(shù)本身也能夠調(diào)用前一個(gè)函數(shù)
            方法:讓參數(shù)接受者去除該項(xiàng)參數(shù),并直接調(diào)用前一個(gè)函數(shù)

            10.9 Introduce Parameter Object(引入?yún)?shù)對(duì)象)295

            動(dòng)機(jī):有些參數(shù)總是自然地同時(shí)出現(xiàn)
            方法:用一個(gè)對(duì)象把這些參數(shù)包裝起來(lái)進(jìn)行傳遞
            目的:

            • 縮短參數(shù)列表長(zhǎng)度;
            • 函數(shù)具有一致性,降低理解和修改代碼的難度

            10.10 Remove Setting Method(移除設(shè)值函數(shù))300

            動(dòng)機(jī):類的某個(gè)字段應(yīng)該對(duì)象創(chuàng)建的時(shí)候被設(shè)置,然后不再改變
            方法:去掉該字段的設(shè)置函數(shù)

            • 如果對(duì)參數(shù)的運(yùn)算很簡(jiǎn)單,而且只有一個(gè)構(gòu)造函數(shù),就可以直接在構(gòu)造函數(shù)中初始化。
            • 如果修改復(fù)雜,或者有多個(gè)函數(shù)試圖改變這個(gè)字段,那么就需要提供一個(gè)獨(dú)立函數(shù),并給予獨(dú)立函數(shù)一個(gè)清楚表達(dá)用途的名字
            • 如果是子類希望修改超類的字段
              • 那么最好是使用超類的構(gòu)造器實(shí)現(xiàn)改變;
              • 或者通過(guò)擁有能夠清楚表達(dá)用途的名字的函數(shù)來(lái)實(shí)現(xiàn)。
            • 如果修改集合字段,請(qǐng)使用Encapsulate Collection(208)實(shí)現(xiàn)。

            10.11 Hide Method(隱藏函數(shù))303

            動(dòng)機(jī):有一個(gè)函數(shù),從來(lái)沒(méi)有被任何類調(diào)用
            方法:將該函數(shù)設(shè)為private
            補(bǔ)充:函數(shù)可見(jiàn)度不夠,在編譯的時(shí)候就可以發(fā)現(xiàn);而函數(shù)過(guò)見(jiàn)度過(guò)高,則需要通過(guò)一些工具(Lint)來(lái)輔助檢查。

            10.12 Replace Constructor with Factory Method(以工廠函數(shù)取代構(gòu)造函數(shù))304

            動(dòng)機(jī):創(chuàng)建對(duì)象時(shí)不僅僅是做簡(jiǎn)單的構(gòu)建動(dòng)作方法:將構(gòu)造函數(shù)替換為工廠模式范例:

            • 根據(jù)整數(shù)(實(shí)際是類型碼)創(chuàng)建對(duì)象;
            • 根據(jù)字符串創(chuàng)建子類對(duì)象;
            • 以函數(shù)創(chuàng)建子類;

            10.13 Encapsulate Downcast(封裝向下轉(zhuǎn)型)308

            動(dòng)機(jī):某個(gè)函數(shù)返回的對(duì)象,需要由函數(shù)調(diào)用者執(zhí)行向下轉(zhuǎn)型(downcast)
            方法:將向下轉(zhuǎn)型移到函數(shù)中

            10.14 Replace Error Code with Exception(以異常取代錯(cuò)誤碼)310

            動(dòng)機(jī):某個(gè)函數(shù)返回一個(gè)特定的代碼,表示某個(gè)錯(cuò)誤的情況
            方法:取消那個(gè)代碼判斷,改用拋出異常
            范例:

            • 非受控異常:使用守衛(wèi)語(yǔ)句檢查這個(gè)異常情況;
            • 受控異常:需要修改的調(diào)用者函數(shù)和被調(diào)用者函數(shù),步驟太大,容易出錯(cuò)。可以先創(chuàng)建一個(gè)臨時(shí)的中間函數(shù),保留原函數(shù),使所有的調(diào)用都改為新函數(shù)后,刪除原函數(shù),再修改新函數(shù)名稱,即可。

            10.15 Replace Exception with Test(以測(cè)試取代異常)315

            動(dòng)機(jī):本該由調(diào)用者自行檢查的條件,由被調(diào)用者拋出了一個(gè)可控異常。
            方法:修改調(diào)用者,使它在調(diào)用函數(shù)之前做檢查。
            補(bǔ)充:異常就應(yīng)該放在可能發(fā)生異常的地方使用。即可以預(yù)測(cè)的,可以通過(guò)檢查避免的,那就是錯(cuò)誤,不該發(fā)生;不能預(yù)測(cè)的,無(wú)法通過(guò)檢查避免的,那就是異常。例如:賬戶余額小于取錢數(shù)目,申請(qǐng)取錢這個(gè)就是錯(cuò)誤;賬戶余額大于取錢數(shù)目,取不出錢來(lái)就是異常。

            第11章 處理概括關(guān)系 319

            概括關(guān)系(generalization,即繼承關(guān)系、泛化關(guān)系)

            11.1 Pull Up Field(字段上移)320

            動(dòng)機(jī):兩個(gè)子類擁有相同的字段
            方法:

            • 將該字段移動(dòng)到超類,去除重復(fù)數(shù)據(jù)聲明;
            • 將使用該字段的行為搬移到超類,去除關(guān)于這個(gè)字段的重復(fù)行為。
            • 考慮對(duì)超類的該字段使用Self Encapsulate Field(171)

            11.2 Pull Up Method(函數(shù)上移)322

            動(dòng)機(jī):有些函數(shù),在各個(gè)子類產(chǎn)生相同的結(jié)果。
            方法:

            • 將該函數(shù)移動(dòng)到超類
            • 如果被提升的函數(shù)引用了子類中的函數(shù)
              • 如果可以將引用函數(shù)提升,就一起提升
              • 如果不可以將引用函數(shù)提升,可以在超類里面那個(gè)抽象函數(shù)

            11.3 Pull Up Constructor Body(構(gòu)造函數(shù)本體上移)325

            動(dòng)機(jī):你在各個(gè)子類擁有一些構(gòu)造函數(shù),它們的本地幾乎完全一致
            方法:在超類新建一個(gè)構(gòu)造函數(shù),并在子類構(gòu)造函數(shù)中調(diào)用它。
            具體方法:

            • 將共同代碼放在子類構(gòu)造函數(shù)起始處,然后再?gòu)?fù)制到超類構(gòu)造函數(shù)中。
            • 將子類構(gòu)造函數(shù)中共同代碼刪除,改用調(diào)用新建的超類構(gòu)造函數(shù)。

            11.4 Push Down Method(函數(shù)下移)328

            動(dòng)機(jī):超類中的某個(gè)函數(shù)只與部分而非全部子類有關(guān)
            方法:將這個(gè)函數(shù)移到相關(guān)的子類去。

            11.5 Push Down Field(字段下移)329

            動(dòng)機(jī):超類中的某個(gè)字段只被部分而非全部子類使用
            方法:將這個(gè)字段移到需要它的那些子類去。

            11.6 Extract Subclass(提煉子類)330

            動(dòng)機(jī):類中的某些特性只被部分實(shí)例用到。
            方法:新建一個(gè)子類,將上面所說(shuō)的那一部分特性移到子類中。
            具體情況:

            • 并不是出現(xiàn)類型碼就表示需要用到子類,可以在委托和繼承之間做選擇。
            • 為子類新建構(gòu)造函數(shù),
              • 子類構(gòu)造函數(shù)與超類構(gòu)造函數(shù)擁有相同的參數(shù)列表,并且直接調(diào)用超類構(gòu)造函數(shù)
              • 如果需要隱藏子類,可使用Replace Constructor with Factory Method(以工廠函數(shù)取代構(gòu)造函數(shù))
            • 找出超類調(diào)用點(diǎn)
              • 如果超類構(gòu)造函數(shù)與子類不同,通過(guò)rename method方法可以解決。
              • 如果不需要超類實(shí)例,可以將超類聲明為抽象類。
            • 逐一使用函數(shù)下移和字段下移將源類的特性移動(dòng)到子類。

            11.7 Extract Superclass(提煉超類)336

            動(dòng)機(jī):兩個(gè)類有相似特性。
            方法:為兩個(gè)類建立一個(gè)超類,將相同特性移至超類。
            補(bǔ)充:Extract Class,Extract Subclass,Extract Superclass對(duì)比學(xué)習(xí)。

            11.8 Extract Interface(提煉接口)341

            動(dòng)機(jī):多個(gè)用戶只使用類接口中的同一子集,或者兩個(gè)類的接口有部分相同。
            方法:將相同子集提煉到獨(dú)立的接口中。
            區(qū)別:提煉超類是提煉共同代碼,提煉接口時(shí)提煉共同接口。
            具體動(dòng)機(jī):如果某個(gè)類在不同環(huán)境下扮演截然不同的角色,使用接口就是個(gè)好主意。接口還能幫助類隱藏一些對(duì)外的函數(shù)接口。

            11.9 Collapse Hierarchy(折疊繼承體系)344

            動(dòng)機(jī):超類和子類之間區(qū)別不大。
            方法:將它們合為一體。

            11.10 Form TemPlate Method(塑造模板函數(shù))344

            動(dòng)機(jī):你有一些子類,其中相應(yīng)的函數(shù)以相同順序執(zhí)行類似的操作,但各個(gè)操作的細(xì)節(jié)有所不同。
            方法:將這些小操作分別放進(jìn)獨(dú)立函數(shù)中,并保持它們都有相同的簽名,于是原函數(shù)也變得相同了。然后將原函數(shù)上移至超類,運(yùn)用多態(tài)來(lái)避免重復(fù)代碼。這樣的原函數(shù)就是Template Method。
            原因:雖然使用了繼承,但是函數(shù)重復(fù)應(yīng)盡量避免。

            11.11 Replace inherited with Delegation(以委托取代繼承)352

            動(dòng)機(jī):某個(gè)子類只使用超類接口中一部分,或是根本不需要繼承而來(lái)的數(shù)據(jù)方法:在子類中新建一個(gè)字段用以保存超類,調(diào)整子類函數(shù),令它委托超類,然后去掉兩者之間的繼承關(guān)系。

            11.12 Replace Delegation with Inherited(以繼承取代委托)352

            動(dòng)機(jī):在兩個(gè)類之間使用委托關(guān)系,并經(jīng)常為整個(gè)接口編寫許多極簡(jiǎn)單的委托函數(shù),方法:讓委托類繼承受托類。注意:

            • 如果并沒(méi)有使用受托類的所有函數(shù),那么就不要使用這個(gè)方法。因?yàn)樽宇悜?yīng)該總是遵循超類的接口,如果委托過(guò)多可以通過(guò)Remove Middle Man(160)方法讓客戶端調(diào)用受托函數(shù),或者Extract Superclass(336)讓兩個(gè)類的接口提煉到超類中;還可以使用Extract Interface(341)方法。
            • 如果受托對(duì)象被不止一個(gè)其他對(duì)象共享,而且受托對(duì)象是可變的時(shí)候,那么這種情況下,不能將委托關(guān)系替換為繼承關(guān)系,因?yàn)檫@樣就無(wú)法共享數(shù)據(jù)了。數(shù)據(jù)共享是委托關(guān)系的一種重要功能。
          • posted on 2019-01-16 17:50 zYx.Tom 閱讀(254) 評(píng)論(0)  編輯  收藏 所屬分類: 7.學(xué)習(xí)日志

            主站蜘蛛池模板: 盐亭县| 盖州市| 南部县| 长春市| 东乡| 晋宁县| 商城县| 黎城县| 桐梓县| 乌拉特中旗| 泽库县| 万全县| 靖江市| 池州市| 永定县| 常熟市| 兴山县| 将乐县| 桑植县| 潼南县| 原阳县| 旌德县| 广河县| 南充市| 抚顺县| 策勒县| 汝城县| 彭阳县| 合山市| 盐城市| 甘德县| 福州市| 云阳县| 裕民县| 金门县| 永康市| 玉林市| 芦山县| 安宁市| 中卫市| 合作市|