<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java, Only Java!

    統(tǒng)計(jì)

    留言簿(20)

    積分與排名

    好友空間

    文檔技巧

    閱讀排行榜

    評(píng)論排行榜

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      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ǔ)充:對有一群不太合理的函數(shù),可以先內(nèi)聯(lián)為一個(gè)長函數(shù),然后再提煉出合理的小函數(shù)

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

      動(dòng)機(jī):當(dāng)臨時(shí)變量只被一個(gè)簡單的表達(dá)式賦值一次,而且它妨礙其他重構(gòu)方法時(shí),才需要重構(gòu)
      條件:Inline Temp多半是為Replace Temp with Query(以查詢?nèi)〈R時(shí)變量)準(zhǔn)備
      方法:將所有對該變量的引用動(dòng)作替代成對它賦值的表達(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)用。
      具體方法: 將提煉出來的函數(shù)用private修飾,如果獨(dú)立函數(shù)有副作用,那對它進(jìn)行Separate Query from Modifier(將查詢函數(shù)和修改函數(shù)分離)

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

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

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

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

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

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

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

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

      6.9 Substitute Algorithm(替換算法)139

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

      第7章 在對象之間搬移特性141

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

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

      動(dòng)機(jī):類中某個(gè)函數(shù)與其他類交互過多
      方法:將該函數(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)對象;
      • 替換對源字段的引用為目標(biāo)類的取值函數(shù)

      7.3 Extract Class(提煉類)149

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      動(dòng)機(jī):如果數(shù)據(jù)存儲(chǔ)的值代表不同的東西。
      方法:將數(shù)組變成對象,數(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ù)需要訪問這些數(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è)類相互之間都需要對方的數(shù)據(jù),但是相互之間只有一條單向的連接
      這個(gè)重構(gòu)需要添加測試,因?yàn)椤胺聪蛑羔槨焙苋菀自斐苫靵y。
      具體方法:

      • 在被引用類添加字段,保存引用類的指針;
      • 判斷由哪個(gè)類來控制關(guān)聯(lián)關(guān)系;
        • 如果兩者都是引用對象,且關(guān)聯(lián)關(guān)系為“一對多”的關(guān)系,那么就由“擁有單一引用”的對象作為控制者;
        • 如果A對象是B對象的部件,則由B對象負(fù)責(zé)控制關(guān)系;
        • 如果兩者都是引用對象,且關(guān)聯(lián)關(guān)系為“多對多”的關(guān)系,那么隨意確定一個(gè)對象作為控制者。
      • 在被控端建立輔助函數(shù),命名清晰地描述其用途;
        • 如果修改函數(shù)在控制端,則由其負(fù)責(zé)更新反向指針;
        • 如果修改函數(shù)在被控制端,則在控制端建立一個(gè)修改反射指針的函數(shù),由修改函數(shù)調(diào)用其修改反向指針。
        • 兩者是一對多關(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)可能造成僵尸對象,不能被清除釋放內(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)的訪問函數(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ī):面對舊程序中Record數(shù)據(jù)結(jié)構(gòu),新建類取代它
      方法:為該記錄創(chuàng)建一個(gè)“啞”數(shù)據(jù)對象。

      Type Code(類型碼)

      常見于過去的C語言編程中,因?yàn)闆]有枚舉,所以采用類型碼的方式標(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è)類型碼且影響類的行為,但是無法通過繼承消除(類型碼可變化)
      方法:以狀態(tài)對象取代。

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

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

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

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

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

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

      • 將if語句提煉為函數(shù)
      • 將then和else段落提煉為函數(shù)
      • 對于存在嵌套的條件邏輯,先判斷是否可以用Replace Nested Conditional with Guard Clauses(以衛(wèi)語句取代嵌套條件表達(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)備,通過函數(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代替;
      • 也可以通過函數(shù)調(diào)用和return語句來實(shí)現(xiàn)。

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

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

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

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

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

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

      9.8 Introduce Assertion(引入斷言)267

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

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

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

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

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

      動(dòng)機(jī):函數(shù)的名稱不能說明函數(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)到擁有該信息的對象中?
      • 加入新參數(shù)是否合適?
      • 如果需要的參數(shù)過多,是否需要使用Introduce Parameter Object(引入?yún)?shù)對象)?

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

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

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

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

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

      • 任何一個(gè)有返回值的函數(shù)都不應(yīng)該有看得到的副作用。
      • 編碼中主要考慮的不是代碼的效率,而是代碼的易讀性,效率可以在未來上線的時(shí)候再根據(jù)實(shí)際需要調(diào)整。多線程:將修改和查詢函數(shù)封裝在一個(gè)同步函數(shù)中分開調(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ù)值的不同而采取不同的行為
      方法:針對該參數(shù)的每個(gè)可能值,建立獨(dú)立函數(shù)。
      對比:與Parameterize Method(令函數(shù)攜帶參數(shù))相反,但是目的都是把復(fù)雜的邏輯判斷消除 目的:提供清晰的入口。
      如果參數(shù)值對函數(shù)行為影響不大,不應(yīng)該采用此方法。

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

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

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

      動(dòng)機(jī):對象調(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ù)對象)295

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

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

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

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

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

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

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

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

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

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

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

      動(dòng)機(jī):某個(gè)函數(shù)返回的對象,需要由函數(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)語句檢查這個(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(以測試取代異常)315

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

      第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ù)行為。
      • 考慮對超類的該字段使用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ù)起始處,然后再復(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è)子類,將上面所說的那一部分特性移到子類中。
      具體情況:

      • 并不是出現(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ù)與子類不同,通過rename method方法可以解決。
        • 如果不需要超類實(shí)例,可以將超類聲明為抽象類。
      • 逐一使用函數(shù)下移和字段下移將源類的特性移動(dòng)到子類。

      11.7 Extract Superclass(提煉超類)336

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

      11.8 Extract Interface(提煉接口)341

      動(dòng)機(jī):多個(gè)用戶只使用類接口中的同一子集,或者兩個(gè)類的接口有部分相同。
      方法:將相同子集提煉到獨(dú)立的接口中。
      區(qū)別:提煉超類是提煉共同代碼,提煉接口時(shí)提煉共同接口。
      具體動(dòng)機(jī):如果某個(gè)類在不同環(huán)境下扮演截然不同的角色,使用接口就是個(gè)好主意。接口還能幫助類隱藏一些對外的函數(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)來避免重復(fù)代碼。這樣的原函數(shù)就是Template Method。
      原因:雖然使用了繼承,但是函數(shù)重復(fù)應(yīng)盡量避免。

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

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

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

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

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

      主站蜘蛛池模板: 伊人久久五月丁香综合中文亚洲| 日本成人免费在线| 无码国产精品一区二区免费3p| GOGOGO高清免费看韩国| 免费无码又爽又黄又刺激网站| 特黄特色大片免费| 青青免费在线视频| 丰满妇女做a级毛片免费观看| 免费看又黄又爽又猛的视频软件| 处破女第一次亚洲18分钟| WWW亚洲色大成网络.COM| 欧洲美女大片免费播放器视频| 深夜a级毛片免费无码| 久久免费视频一区| 黄色免费在线网站| 最近中文字幕高清免费中文字幕mv| 午夜视频在线免费观看| 91精品全国免费观看含羞草| 18pao国产成视频永久免费| 无码区日韩特区永久免费系列| www.黄色免费网站| 国产在线观看www鲁啊鲁免费| 内射无码专区久久亚洲| 色噜噜AV亚洲色一区二区| 亚洲AV日韩AV永久无码久久 | 2020因为爱你带字幕免费观看全集 | 亚洲国产成人综合| 亚洲日韩一区二区一无码| 国产精品亚洲二区在线| 9久久免费国产精品特黄| 免费女人高潮流视频在线观看| 免费观看AV片在线播放| 国产真人无遮挡作爱免费视频| 国产偷窥女洗浴在线观看亚洲| 亚洲AV无码一区东京热| 亚洲妇女水蜜桃av网网站| 亚洲狠狠色丁香婷婷综合| 国产精品一区二区三区免费 | 深夜福利在线免费观看| 三年片在线观看免费观看大全一| 日韩欧毛片免费视频|