《重構(gòu)》讀書筆記
總覽
第一部分
第一章從實(shí)例程序出發(fā),展示設(shè)計(jì)的缺陷,對(duì)其重構(gòu)可以了解重構(gòu)的過(guò)程和方法济似。
第二部分
第二章討論重構(gòu)的一般性原則猖凛、定義和進(jìn)行重構(gòu)的原因赂蠢。主要講述概念性的東西。
第三部分
第三章介紹如何嗅出代碼的“壞味道”以及如何用重構(gòu)對(duì)其消除辨泳。
第四部分
第四章講述構(gòu)建java的測(cè)試環(huán)境
第五部分
第五章到第十二章介紹作者整理下來(lái)重構(gòu)的方法虱岂。
第六部分
第十三章重構(gòu)技術(shù)在商業(yè)化應(yīng)用中出現(xiàn)的問(wèn)題
第1章 重構(gòu)玖院,第一個(gè)案例1
1.1 起點(diǎn)1
如果發(fā)現(xiàn)需要為程序添加新特性,而代碼結(jié)構(gòu)使你無(wú)法很方便的達(dá)到目的第岖,那就需要先進(jìn)行重構(gòu)难菌,然后使新特性的添加容易進(jìn)行,再添加新特性蔑滓。
1.2 重構(gòu)的第一步7
首先檢查自己是否有一套可靠的測(cè)試機(jī)制郊酒。這些測(cè)試必須有自我檢測(cè)的能力。因?yàn)橹貥?gòu)有可能引入bug键袱。
1.3 分解并重組statement()8
重構(gòu)技術(shù)就是以 微小的步伐修改程序燎窘,如果發(fā)現(xiàn)錯(cuò)誤,很容易可以發(fā)現(xiàn)它蹄咖。
優(yōu)秀的程序員應(yīng)該寫出人類容易理解的代碼褐健,而非僅僅是計(jì)算機(jī)能理解的代碼。
- 搬移金額計(jì)算代碼(Move Method)
- 去除不必要的臨時(shí)變量(Replace Temp with Query)
- 提煉忱教溃客積分計(jì)算(Move Method)
- Move Method 如果一個(gè)方法運(yùn)用目標(biāo)對(duì)象的屬性進(jìn)行計(jì)算蚜迅,那么請(qǐng)把這個(gè)方法抽象到目標(biāo)對(duì)象的類中。
1.4 運(yùn)用多態(tài)取代與價(jià)格相關(guān)的條件邏輯34
- 最好不要在另一個(gè)對(duì)象的屬性基礎(chǔ)上運(yùn)用switch語(yǔ)句俊抵。如果不得不使用谁不,也應(yīng)該在對(duì)象自己的數(shù)據(jù)上使用,而不是別人的數(shù)據(jù)上徽诲。
- 當(dāng)一個(gè)類需要運(yùn)用多態(tài)的時(shí)候刹帕,但是假如其在生命周期內(nèi)有可能變成另一個(gè)同胞類,那么就應(yīng)該使用state設(shè)計(jì)模式來(lái)解決這個(gè)問(wèn)題馏段。
1.5 結(jié)語(yǔ)52
第2章 重構(gòu)原則53
2.1 何謂重構(gòu)53
- 名詞含義:對(duì)軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整轩拨,目的是在不改變軟件可觀察行為的前提下,提高理解性和降低修改成本院喜。
- 動(dòng)詞含義
使用一系列重構(gòu)手法亡蓉,在不改變軟件可觀察行為的前提下,調(diào)整其結(jié)構(gòu)喷舀。 - 重構(gòu)讓軟件更容易理解和修改
- 重構(gòu)不會(huì)改變軟件的可觀察行為砍濒,即使改變也只能是微小的影響,軟件功能一如既往硫麻。
- 兩頂 帽子(時(shí)間分配)
- 添加新功能:不應(yīng)該修改已有代碼爸邢,只關(guān)注新功能。增加新測(cè)試拿愧,通過(guò)測(cè)試衡量工作進(jìn)度
- 重構(gòu):只改變程序內(nèi)部結(jié)構(gòu)杠河,不應(yīng)該添加測(cè)試(存在遺漏),不修改測(cè)試(除非接口發(fā)生變化)
- 軟件開(kāi)發(fā)在這兩者之間切換
2.2 為何重構(gòu)55
-
改進(jìn)軟件設(shè)計(jì):
- 程序的設(shè)計(jì)在沒(méi)有重構(gòu)的情況下逐漸腐敗變質(zhì),功能的增加或者修改可能使代碼越來(lái)越難以理解券敌,就越難保護(hù)其中的設(shè)計(jì)
- 消除重復(fù)的代碼一方面是程序運(yùn)行更快唾戚,一方面是方便未來(lái)的修改,只用在一處修改即可不用修改多處待诅。
-
軟件更容易理解:
- 及時(shí)填補(bǔ)“想要它做什么”和“告訴它做什么”之間的縫隙叹坦。重構(gòu)的核心就是要“準(zhǔn)確說(shuō)出我所要的”
- 重新閱讀代碼的人有可能是自己,他人卑雁。
- 通過(guò)重構(gòu)可以把不熟悉的代碼的用途理一遍募书,加深對(duì)代碼的理解
幫助找出bug:這個(gè)是建立在代碼容易理解之上的
提高編程速度:重構(gòu)達(dá)到良好的設(shè)計(jì),而良好的設(shè)計(jì)更容易修改测蹲,增加功能莹捡,調(diào)試。
2.3 何時(shí)重構(gòu)57
- 三次法則:第一次的時(shí)候做某事盡管去做扣甲。第二次的時(shí)候?qū)λa(chǎn)生反感道盏,還是繼續(xù)去做。第三次再做類似的時(shí)候文捶,就應(yīng)該重構(gòu)了。
- 添加功能時(shí)重構(gòu):一方面可能是需要理解需要修改的代碼媒咳,另一方面是使增加新特性更加容易粹排。
- 修補(bǔ)錯(cuò)誤時(shí)重構(gòu):出現(xiàn)bug的時(shí)候,難以找出問(wèn)題所在的時(shí)候涩澡,很有可能是代碼不清晰導(dǎo)致查找bug的困難顽耳。
- 復(fù)審代碼時(shí)重構(gòu):
- 復(fù)審代碼有助于知識(shí)的傳播,有利于代碼被編寫者之外的人理解妙同。
- 重構(gòu)是有利于增強(qiáng)復(fù)審代碼的能力射富,重構(gòu)需要先閱讀代碼得到一定程度的理解,得到一些建議粥帚,然后動(dòng)手實(shí)現(xiàn)胰耗。所以重構(gòu)有利于知道合理的代碼應(yīng)當(dāng)是怎么樣的。
- 復(fù)審團(tuán)隊(duì)需要精煉芒涡,就 一個(gè)審查者和一個(gè)原作者柴灯。較大的項(xiàng)目可以通過(guò) UML圖去展示代碼的邏輯。
- 程序難以相與的原因:
- 難以閱讀的程序费尽,難以修改
- 邏輯重復(fù)的程序赠群,難以修改
- 添加新特性需要修改已有代碼的程序,難以修改
- 帶復(fù)雜邏輯判斷的程序旱幼,難以修改
- 對(duì)應(yīng)的期望:
- 容易閱讀
- 所有邏輯都只有唯一地點(diǎn)指定
- 新的改動(dòng)不會(huì)危及現(xiàn)有行為
- 盡可能簡(jiǎn)單表達(dá)邏輯
2.4 怎么對(duì)經(jīng)理說(shuō)60
- 不要告訴經(jīng)理:經(jīng)理是進(jìn)度驅(qū)動(dòng)查描,就是要求開(kāi)發(fā)者盡快完成任務(wù)。而對(duì)于我來(lái)說(shuō)最快完成任務(wù)的方式就是先重構(gòu)喝滞。
- 很多時(shí)候重構(gòu)都為程序引入間接層翁垂。把大型對(duì)象拆分成小對(duì)象,把大型函數(shù)拆分為小型函數(shù)蓉冈。
- 允許邏輯共享:一個(gè)函數(shù)在不同地點(diǎn)被調(diào)用长豁。子類共享超類的方法钧唐。
- 分開(kāi)解釋意圖和實(shí)現(xiàn):通過(guò)類名和函數(shù)名解釋自己的意圖
- 隔離變化:在不同地方使用同一個(gè)對(duì)象,需要修改一處邏輯匠襟,那么可以做出子類钝侠,并在需要的時(shí)候修改這個(gè)子類。
- 封裝條件邏輯:運(yùn)用多態(tài)酸舍。將條件邏輯轉(zhuǎn)化為消息模式帅韧。
- 減少間接層:當(dāng)間接層只在一處使用,那么需要將其消除啃勉。
2.5 重構(gòu)的難題62
- 數(shù)據(jù)庫(kù):
- 程序與數(shù)據(jù)庫(kù)耦合在一起忽舟。另一方面是數(shù)據(jù)遷移,是向繁瑣的事項(xiàng)淮阐。
- 在非關(guān)系型數(shù)據(jù)庫(kù)叮阅,可以在數(shù)據(jù)庫(kù)和對(duì)象模型中插入一個(gè)分離層,隔離兩者之間的變化
- 修改接口
- 對(duì)于已經(jīng)發(fā)布的接口需要可能需要維護(hù)舊接口和新接口泣特,用deprecated修飾舊接口浩姥。
- 不發(fā)布新接口,在舊接口中調(diào)用新接口状您。
- 假如新接口拋出編譯時(shí)異常勒叠,那么可以在舊接口中調(diào)用新接口并將編譯時(shí)異常轉(zhuǎn)化為運(yùn)行時(shí)異常。
- 何時(shí)不重構(gòu)
- 重構(gòu)之前膏孟,代碼必須能夠在大部分情況下 正常運(yùn)行眯分,不然就不應(yīng)該重構(gòu),而應(yīng)該是 重寫柒桑。
- 到了Deadline弊决,應(yīng)該避免重構(gòu)。
2.6 重構(gòu)與設(shè)計(jì)66
- 重構(gòu)與設(shè)計(jì)是彼此互補(bǔ)的幕垦。
- 預(yù)先設(shè)計(jì)是必須丢氢,預(yù)先設(shè)計(jì)不可能做到完全正確,隨著對(duì)問(wèn)題的逐漸深入先改,通過(guò)重構(gòu)可以改善程序的質(zhì)量疚察。
- 重構(gòu)減輕了設(shè)計(jì)的難度和壓力,在程序不斷修改的過(guò)程逐步完善程序的設(shè)計(jì)仇奶。
2.7 重構(gòu)與性能69
- 重構(gòu)是有可能導(dǎo)致程序運(yùn)行變慢的貌嫡。
- 除了對(duì)實(shí)時(shí)有嚴(yán)格要求的程序比驻,編寫快速軟件的秘訣是:首先寫出可調(diào)的程序,然后調(diào)整它以達(dá)到足夠的速度岛抄。
- 經(jīng)過(guò)分析大部分程序的大半部分時(shí)間是運(yùn)行在一小半代碼上别惦,所以對(duì)所有代碼一視同仁是錯(cuò)誤的。
- 性能優(yōu)化放在開(kāi)發(fā)的后期夫椭,通過(guò)分析工具找出消耗大量時(shí)間空間的地方掸掸,然后集中精力優(yōu)化這些地方。
2.8 重構(gòu)起源何處71
第3章 代碼的壞味道75
3.1 DuplicatedCode(重復(fù)代碼)76
- 同個(gè)類兩個(gè)函數(shù)存在相同表達(dá)式:ExtractMethod(提煉函數(shù))
- 互為兄弟類內(nèi)存在相同表達(dá)式:
- ExtractMethod-》PullUpMethod(函數(shù)上移)
- 如果代碼只是相似:先運(yùn)用ExtractMethod(提煉函數(shù))分開(kāi)再Form TemPlate Method(塑造模板函數(shù))
- 兩個(gè)毫不相干的類存在重復(fù)代碼:ExtractClass(提煉類)
3.2 LongMethod(過(guò)長(zhǎng)函數(shù))76
- 原則:每當(dāng)感覺(jué)需要以注釋來(lái)說(shuō)明什么的時(shí)候蹭秋,我就將需要說(shuō)明的代碼放到一個(gè)獨(dú)立的函數(shù)里面
- 只要函數(shù)名稱能夠 解釋用途扰付,我們就應(yīng)該毫不猶豫地做。
- 關(guān)鍵不在函數(shù)的長(zhǎng)度仁讨,而在于函數(shù)“做什么”和“如何做”之間的語(yǔ)義距離羽莺。
- 具體情況
- 函數(shù)有大量參數(shù)和臨時(shí)變量:ExtractMethod(提煉函數(shù))
- 用ReplaceTempwithQuery(以查詢?nèi)〈R時(shí)變量)消除臨時(shí)變量
- 用IntroduceParameterObject(引入?yún)?shù)對(duì)象)或者PreserveWholeObject(保持對(duì)象完整)來(lái)將多長(zhǎng)的參數(shù)列表變得簡(jiǎn)潔一點(diǎn)。
- 如果按照上述步驟還存在太多變量和參數(shù)就需要用到ReplaceMethodwithMethodObject(以函數(shù)對(duì)象取代函數(shù))
- 條件表達(dá)式可以用DecomposeConditional(分解條件表達(dá)式)解決
- 可以將循環(huán)內(nèi)的代碼提煉為函數(shù)洞豁。
3.3 LargeClass(過(guò)大的類)78
- 有時(shí)候類并非在所有時(shí)刻都使用實(shí)例變量:使用ExtractMethod和ExtractSubclass(提煉子類)
- 類中有太多代碼:ExtractClass(提煉類)ExtractSubclass(提煉子類)盐固,甚至可以使用提煉接口的方式分解類的行為。
- 存在GUI的時(shí)候丈挟,可以DuplicateObservedData(復(fù)制“被監(jiān)視數(shù)據(jù)”)刁卜,分離數(shù)據(jù)和行為到領(lǐng)域模型中去。
3.4 LongParameterList(過(guò)長(zhǎng)參數(shù)列)78
- 如果可以調(diào)用已有對(duì)象獲取的話可以使用ReplaceParameterwithMethods(以函數(shù)取代參數(shù))
- 將來(lái)自同一對(duì)象的數(shù)據(jù)收集起來(lái)曙咽,以該對(duì)象替代:PreserveWholeObject(保持對(duì)象完整)
- 如果幾個(gè)參數(shù)總是同時(shí)出現(xiàn)长酗,那么可以考慮IntroduceParameterObject(引入?yún)?shù)對(duì)象)
3.5 DivergentChange(發(fā)散式變化)79
- 一個(gè)類受多種變化影響:加上一個(gè)功能需要修改類中多個(gè)函數(shù)
- 目標(biāo)是每個(gè)對(duì)象都可以只因一種變化而需要修改
- 方法:可以將提煉類來(lái)達(dá)到。
3.6 ShotgunSurgery(霰彈式修改)80
- 遇到某種變化桐绒,需要在許多不同類做小修改。
- 可以通過(guò)移動(dòng)函數(shù)之拨、移動(dòng)字段茉继、內(nèi)聯(lián)類把一種變化一系列變化放到同一個(gè)類中。
- 對(duì)比:DivergentChange(發(fā)散式變化)是一個(gè)類受多個(gè)變化影響蚀乔;ShotgunSurgery(霰彈式修改)是一個(gè)變化引起多個(gè)類相應(yīng)修改烁竭。
3.7 FeatureEnvy(依戀情結(jié))80
- 函數(shù)對(duì)某個(gè)類的興趣高過(guò)對(duì)自己類的興趣
- 通過(guò)移動(dòng)函數(shù)放到該合適的位置。
3.8 DataClumps(數(shù)據(jù)泥團(tuán))81
- 數(shù)據(jù)項(xiàng)總是成群結(jié)隊(duì)出現(xiàn)
- 判斷方法:刪除眾多數(shù)據(jù)項(xiàng)的一項(xiàng)吉挣,這么做其他數(shù)據(jù)是否失去意義派撕。如果不再有意義就需要提煉為參數(shù)對(duì)象。
3.9 PrimitiveObsession(基本類型偏執(zhí))81
- 有些字段可以用對(duì)象表示更準(zhǔn)確ReplaceDataValuewithObject(以對(duì)象取代數(shù)據(jù)值)
- 對(duì)于不影響行為的類型碼可以ReplaceTypeCodewithClass(以類取代類型碼)
- 影響行為的類型碼可以ReplaceTypeCodewithSubclasses(以子類取代類型碼)睬魂,類型碼在運(yùn)行時(shí)會(huì)變化就用ReplaceTypeCodewithState/Strategy(以State/Strategy取代類型碼)
3.10 SwitchStatements(switch驚悚現(xiàn)身)82
- 使用ReplaceTypeCodewithSubclasses(以子類取代類型碼)或者ReplaceTypeCodewithState/Strategy(以State/Strategy取代類型碼)
- 輕量級(jí)的解決方法:ReplaceParameterwithExplicitMethods(以明確函數(shù)取代參數(shù))
3.11 ParallelInheritanceHierarchies(平行繼承體系)83
- 每當(dāng)為一個(gè)類增加子類必須也為另外一個(gè)類增加一個(gè)子類
- 策略是讓一個(gè)繼承體系的實(shí)例引用另一個(gè)繼承體系的實(shí)例终吼。
3.12 LazyClass(冗贅類)83
- 內(nèi)聯(lián)類或者Collapse Hierarchy(折疊繼承體系)來(lái)解決
3.13 SpeculativeGenerality(夸夸其談未來(lái)性)83
- 內(nèi)聯(lián)類或者Collapse Hierarchy(折疊繼承體系)來(lái)解決
- 函數(shù)參數(shù)沒(méi)被用上RemoveParameter(移除參數(shù))
- 函數(shù)名稱過(guò)于抽象RenameMethod(函數(shù)改名)
3.14 TemporaryField(令人迷惑的暫時(shí)字段)84
- 對(duì)象中某個(gè)字段僅為特定情況而設(shè)。
- 提煉類來(lái)解決
3.15 MessageChains(過(guò)度耦合的消息鏈)84
- 獲取一個(gè)對(duì)象氯哮,再通過(guò)該對(duì)象獲取另外一個(gè)對(duì)象進(jìn)行操作:HideDelegate(隱藏“委托關(guān)系”)
3.16 MiddleMan(中間人)85
- 過(guò)度委托形成中間人:RemoveMiddleMan(移除中間人)
- 如果中間人還有其他行為,Replace Delegation with Inherited(以繼承取代委托)
3.17 InappropriateIntimacy(狎昵關(guān)系)85
- 兩個(gè)類過(guò)于親密际跪,花費(fèi)太多時(shí)間去探究彼此private成分
- 移動(dòng)字段和移動(dòng)方法減少狎昵
- ChangeBidirectionalAssociationtoUnidirectional(將雙向關(guān)聯(lián)改為單向關(guān)聯(lián))
- 如果兩個(gè)類實(shí)在情投意合:可以使用ExtractClass(提煉類),讓他們使用新類進(jìn)行交互。
3.18 AlternativeClasseswithDifferentInterfaces(異曲同工的類)85
- 兩個(gè)函數(shù)做了相同的事情卻有不同的簽名
3.19 IncompleteLibraryClass(不完美的庫(kù)類)86
- 庫(kù)函數(shù)不夠好,需要加入一些操作姆打,其實(shí)類似于 適配IntroduceForeignMethod(引入外加函數(shù))
- 如果需要加入大量的操作良姆,IntroduceLocalExtension(引入本地?cái)U(kuò)展)
3.20 DataClass(純稚的數(shù)據(jù)類)86
- 類只有數(shù)據(jù)沒(méi)有行為,其他類存在對(duì)該類的數(shù)據(jù)進(jìn)行取值設(shè)值操作
- 有public字段:EncapsulateField(封裝字段)
- 對(duì)于不該被其他類修改的字段:RemoveSettingMethod(移除設(shè)值函數(shù))
3.21 RefusedBequest(被拒絕的遺贈(zèng))87
- 如果類不想得到另一個(gè)類全部東西幔戏,只對(duì)部分感興趣玛追。
- 可以使用Replace inherited with Delegation(以委托取代繼承)來(lái)處理
3.22 Comments(過(guò)多的注釋)87
- 試試提煉方法來(lái)解決注釋過(guò)多問(wèn)題
第4章 構(gòu)筑測(cè)試體系89
4.1 自測(cè)試代碼的價(jià)值89
4.2 JUnit測(cè)試框架91
4.3 添加更多測(cè)試97
第5章 重構(gòu)列表103
5.1 重構(gòu)的記錄格式103
5.2 尋找引用點(diǎn)105
5.3 這些重構(gòu)手法有多成熟106
第6章 重新組織函數(shù)109
6.1 ExtractMethod(提煉函數(shù))110
- 無(wú)局部變量:直接抽取方法
- 含有局部變量
- 局部變量只在提煉代碼塊內(nèi)被讀取值:將局部變量作為方法參數(shù)
- 局部變量在提煉代碼塊內(nèi)被賦值:1只在提煉代碼內(nèi)被使用->將局部變量提煉到新該方法內(nèi);2在提煉代碼塊后->使用就返回局部變量修改后的值
6.2 InlineMethod(內(nèi)聯(lián)函數(shù))117
- 當(dāng)函數(shù)的名稱與其本體都一眼清晰明了,在函數(shù)調(diào)用點(diǎn)插入函數(shù)本體闲延,移除該函數(shù)痊剖。
- 有一群不甚合理的函數(shù),可以先內(nèi)聯(lián)到大型函數(shù)然后再提煉出合理的小函數(shù)
6.3 InlineTemp(內(nèi)聯(lián)臨時(shí)變量)119
- 當(dāng)臨時(shí)變量只是被一個(gè)簡(jiǎn)單表達(dá)式賦值一次慨代,而它妨礙其他重構(gòu)方法
- 方法:將所有對(duì)該變量的引用動(dòng)作替代成對(duì)它賦值的表達(dá)式本身邢笙。
- 情形:
- InlineTemp多半是為ReplaceTempwithQuery(以查詢?nèi)〈R時(shí)變量)準(zhǔn)備
- 臨時(shí)變量被一次賦值后,臨時(shí)變量作為函數(shù)的返回值侍匙。
6.4 ReplaceTempwithQuery(以查詢?nèi)〈R時(shí)變量)120
- 情況:你的程序以一個(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)行SeparateQueryfromModifier(將查詢函數(shù)和修改函數(shù)分離)
6.5 IntroduceExplainingVariable(引入解釋性變量)124
- 將復(fù)雜表達(dá)式的結(jié)果賦值給一個(gè)臨時(shí)變量,用臨時(shí)變量名稱來(lái)解釋表達(dá)式的用途
6.6 SplitTemporaryVariable(分解臨時(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 RemoveAssignmentstoParameters(移除對(duì)參數(shù)的賦值)131
- java是值傳遞储狭,對(duì)參數(shù)的任何修改都不會(huì)再調(diào)用端造成影響互婿,所以對(duì)于 用過(guò)引用傳遞的人可能會(huì)發(fā)生理解錯(cuò)誤
- 參數(shù)應(yīng)該僅表示“被傳遞過(guò)來(lái)的東西”
6.8 ReplaceMethodwithMethodObject(以函數(shù)對(duì)象取代函數(shù))135
- 情形:在大型函數(shù)內(nèi),對(duì)局部變量的使用導(dǎo)致難以使用ExtractMethod(提煉函數(shù))進(jìn)行重構(gòu)
- 做法:將這個(gè)函數(shù)放入一個(gè)對(duì)象里辽狈,局部變量變成對(duì)象成員變量慈参,然后可以在同一對(duì)象中將這個(gè)大型函數(shù)分解為多個(gè)小型函數(shù)。
- 原因:局部變量會(huì)增加分解函數(shù)的困難度
6.9 SubstituteAlgorithm(替換算法)139
- 把某個(gè)算法替換成更清晰的做法(算法)(有點(diǎn)廢話)刮萌。
第7章 在對(duì)象之間搬移特性141
7.1 MoveMethod(搬移函數(shù))142
- 情形:程序中有個(gè)函數(shù)與所駐類之外的另一個(gè)類進(jìn)行更多交流驮配,調(diào)用后者或者后者調(diào)用該函數(shù)
- 做法:在該函數(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 MoveField(搬移字段)146
- 情形:程序中有個(gè)字段與所駐類之外被另一個(gè)類使用(包括設(shè)置取值函數(shù)的間接調(diào)用)尸变,后者調(diào)用該字段
- 做法:將該字段搬移到目標(biāo)類
- 具體做法:建立從“舊類訪問(wèn)新類”的連接關(guān)系义图,除非真正需要 不要建立從“新類到舊類”的關(guān)系
7.3 ExtractClass(提煉類)149
- 情形:一個(gè)類做了兩個(gè)類的事
- 做法:建立新類,將相應(yīng)的字段和函數(shù)放到新類
7.4 InlineClass(將類內(nèi)聯(lián)化)154
- 情形:某個(gè)類沒(méi)做太多的事情召烂,與ExtractClass(提煉類)相反
- 做法:將這個(gè)類的所有特性搬移到另一類中碱工,移除該類。
- 判斷依據(jù):當(dāng)一個(gè)類不再承擔(dān)足夠責(zé)任
7.5 HideDelegate(隱藏“委托關(guān)系”)157
- 情形:客戶端通過(guò)委托類來(lái)調(diào)用另一個(gè)對(duì)象
- 做法:在服務(wù)類上建立客戶端所需的函數(shù)奏夫,然后隱藏委托關(guān)系
- 依據(jù):符合“封裝”的特性怕篷。當(dāng)委托類發(fā)生變化不會(huì)對(duì)客戶端造成影響
7.6 RemoveMiddleMan(移除中間人)160
- 情形:某個(gè)類做了過(guò)多的委托動(dòng)作
- 做法:讓客戶端直接調(diào)用委托類
- 依據(jù):當(dāng)原委托類的特性越來(lái)越多,服務(wù)類的委托函數(shù)將越來(lái)越長(zhǎng)酗昼,需要讓客戶端直接調(diào)用廊谓,避免服務(wù)類淪為中間人。
7.7 IntroduceForeignMethod(引入外加函數(shù))162
- 情形:需要為服務(wù)類某個(gè)函數(shù)增加功能麻削,但是不能修改該類
- 做法:新建函數(shù)并將服務(wù)類的對(duì)象實(shí)例作為參數(shù)傳入蒸痹。
- 具體情形:如果需要為服務(wù)類增加 大量的方法,請(qǐng)考慮使用IntroduceLocalExtension(引入本地?cái)U(kuò)展)
7.8 IntroduceLocalExtension(引入本地?cái)U(kuò)展)164
- 情形:需要為服務(wù)類某個(gè)函數(shù)增加函數(shù)呛哟,但是不能修改該類
- 做法:建立新類叠荠,使它包括這些額外函數(shù),讓這個(gè)擴(kuò)展類作為服務(wù)類的子類或者包裝類扫责。
- 具體情況:如果需要對(duì)數(shù)據(jù)進(jìn)行修改要波及服務(wù)類對(duì)象榛鼎,那么使用包裝類的方式。如果不需要鳖孤,使用子類化的方式
第8章 重新組織數(shù)據(jù)169
8.1 SelfEncapsulateField(自封裝字段)171
- 情形:直接訪問(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)的好處
- 修改獲取數(shù)據(jù)的途徑肺然;
- 支持更靈活的數(shù)據(jù)管理;如延遲加載(需要用到才加載)等腿准。
- 直接訪問(wèn)的好處
- 容易閱讀代碼,不會(huì)需要轉(zhuǎn)換一下這個(gè)函數(shù)是取值函數(shù)拾碌。
8.2 ReplaceDataValuewithObject(以對(duì)象取代數(shù)據(jù)值)175
- 情形:假如一個(gè)數(shù)據(jù)項(xiàng)需要與其他數(shù)據(jù)一起使用才有意義吐葱。
- 做法:將數(shù)據(jù)變成對(duì)象。
8.3 ChangeValuetoReference(將值對(duì)象改為引用對(duì)象)179
- 情形:從一個(gè)類衍生出彼此相似的對(duì)象的實(shí)例校翔,希望把它們替換為同一個(gè)對(duì)象弟跑,ps:方便統(tǒng)一修改
- 做法:將值對(duì)象變成引用對(duì)象
- 區(qū)別:
- 引用對(duì)象每個(gè)都對(duì)應(yīng)現(xiàn)實(shí)中一個(gè)對(duì)象(==)
- 值對(duì)象只關(guān)心其值是否相等。(重寫equals()和hashcode()方法)
- 具體做法:
- 需要使用工廠模式來(lái)創(chuàng)建對(duì)象
- 需要一個(gè)類(或者是自身)用字典或者靜態(tài)表來(lái)保存對(duì)象
- 決定對(duì)象是預(yù)先創(chuàng)建還是動(dòng)態(tài)創(chuàng)建
8.4 ChangeReferencetoValue(將引用對(duì)象改為值對(duì)象)183
- 情形:有一個(gè)引用對(duì)象且 很小(創(chuàng)建太多值對(duì)象內(nèi)存消耗大) 不可變(無(wú)需修改對(duì)象)防症,那么應(yīng)該將其轉(zhuǎn)換為值對(duì)象
- 具體做法:
- 查看是否是不可變對(duì)象或者可修改成不可變對(duì)象
- 重寫hashCode和equals()方法
- 取消使用工廠模式和將對(duì)象的構(gòu)造函數(shù)設(shè)為public
8.5 ReplaceArraywithObject(以對(duì)象取代數(shù)組)186
- 情形:如果數(shù)據(jù)存儲(chǔ)了不相似的數(shù)據(jù)孟辑,元素代表不同的東西哎甲。
- 做法:將數(shù)組變成對(duì)象,數(shù)組的每個(gè)元素用字段表示
8.6 DuplicateObservedData(復(fù)制“被監(jiān)視數(shù)據(jù)”)189
- 情形: 有領(lǐng)域數(shù)據(jù)置身于GUI控件中饲嗽,而領(lǐng)域函數(shù)需要訪問(wèn)這些數(shù)據(jù)
- 做法:將該數(shù)據(jù)復(fù)制到領(lǐng)域模型中炭玫。建立Observer模式,同步UI和領(lǐng)域模型的數(shù)據(jù)貌虾。
8.7 ChangeUnidirectionalAssociationtoBidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))197
- 情形:被引用類需要得到引用類做一些處理
- 具體做法:
- 兩者是一對(duì)多關(guān)系吞加,有單一引用承擔(dān)控制關(guān)聯(lián)關(guān)系責(zé)任
- 如果某個(gè)對(duì)象(Task)是另一個(gè)對(duì)象(Project)的組件,由后者負(fù)責(zé)控制尽狠。
- 如果兩者之間都是多對(duì)多關(guān)系衔憨,那么由誰(shuí)負(fù)責(zé)都沒(méi)關(guān)系
8.8 ChangeBidirectionalAssociationtoUnidirectional(將雙向關(guān)聯(lián)改為單向關(guān)聯(lián))200
- 情形:兩個(gè)類有雙向關(guān)聯(lián),但是一個(gè)類不關(guān)心另一個(gè)類的特性
- 做法:去除雙向關(guān)聯(lián)
- 原因:
- 雙向關(guān)聯(lián)可能造成僵尸對(duì)象袄膏,不能被清除釋放內(nèi)存践图。
- 使兩個(gè)類存在耦合關(guān)系,一個(gè)類的變化會(huì)導(dǎo)致另一類的變化沉馆。
8.9 ReplaceMagicNumberwithSymbolicConstant(以字面常量取代魔法數(shù))204
- 情形:有一個(gè)字面常量(除了0和1之外)
- 做法:創(chuàng)建常量賦值以該字面常量码党,給予命名。
8.10 EncapsulateField(封裝字段)206
- 情形:一個(gè)類有public字段
- 將它聲明為private悍及,并提供相應(yīng)的訪問(wèn)函數(shù)
8.11 EncapsulateCollection(封裝集合)208
- 情形:有函數(shù)返回集合
- 做法:讓該函數(shù)返回只讀副本闽瓢,并在該類提供增加和刪除集合元素的函數(shù)
- 具體做法:不應(yīng)該提供集合的設(shè)值函數(shù)
8.12 ReplaceRecordwithDataClass(以數(shù)據(jù)類取代記錄)217
- 情形:面對(duì)傳統(tǒng)編程環(huán)境的記錄數(shù)據(jù)
- 做法:為該記錄創(chuàng)建一個(gè)“啞”數(shù)據(jù)對(duì)象。
8.13 ReplaceTypeCodewithClass(以類取代類型碼)218
- 情形:類中有個(gè)數(shù)值型類型碼心赶,不影響類的行為
- 做法:以一個(gè)新類替代類型碼
8.14 ReplaceTypeCodewithSubclasses(以子類取代類型碼)223
- 情形:有一個(gè)不可變的類型碼且影響類的行為
- 做法:以子類取代這個(gè)類型碼
8.15 ReplaceTypeCodewithState/Strategy(以State/Strategy取代類型碼)227
- 情形:有一個(gè)類型碼且影響類的行為扣讼,但是無(wú)法通過(guò)繼承消除(類型碼可變化)
- 做法:以狀態(tài)對(duì)象取代。
8.16 ReplaceSubclasswithFields(以字段取代子類)232
- 情形:各個(gè)子類唯一區(qū)別只在“返回常量的數(shù)據(jù)”的函數(shù)上
- 做法:修改這些函數(shù)使它們返回超類的某個(gè)(新增)字段缨叫,然后銷毀子類椭符。
第9章 簡(jiǎn)化條件表達(dá)式237
9.1 DecomposeConditional(分解條件表達(dá)式)238
- 情形:if-then-else語(yǔ)句,不同分支做不同事情形成大型函數(shù)耻姥,本身就難以閱讀销钝,尤其在帶有復(fù)雜條件的邏輯中。
- 做法:
- 將if語(yǔ)句提煉為函數(shù)
- 將then和else段落提煉為函數(shù)
- 存在 嵌套琐簇,先判斷是否可以用ReplaceNestedConditionalwithGuardClauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)消除蒸健。不行再分解每個(gè)條件
9.2 ConsolidateConditionalExpression(合并條件表達(dá)式)240
- 情形:有一系列條件判斷都返回相同結(jié)果
- 做法:將這些測(cè)試合并為同一個(gè)表達(dá)式并將這個(gè)表達(dá)式提煉為獨(dú)立函數(shù)
- 原因:
- 只是一次檢查,只是存在并列條件需要檢查而已
- 為ExtractMethod(提煉函數(shù))做準(zhǔn)備婉商,通過(guò) 函數(shù)名 告知“為什么這么做”
- 特殊情形:條件表達(dá)式 存在副作用似忧。
9.3 ConsolidateDuplicateConditionalFragments(合并重復(fù)的條件片段)243
- 情形:在條件表達(dá)式的分支上有相同的代碼
- 做法:將這段重復(fù)代碼搬移到條件表達(dá)式之外,多行代碼可以提煉為獨(dú)立函數(shù)丈秩。
- 當(dāng)try和catch執(zhí)行相同代碼盯捌,可以將代碼移到final區(qū)段。
9.4 RemoveControlFlag(移除控制標(biāo)記)245
- 情形:在一系列布爾表達(dá)式中蘑秽,某個(gè)變量存在控制標(biāo)記(control flag)作用饺著。
- 做法:以break或者continue代替
9.5 ReplaceNestedConditionalwithGuardClauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)250
- 情形:函數(shù)中的條件邏輯使人難以看清正確的執(zhí)行路徑箫攀。
- 做法:使用衛(wèi)語(yǔ)句表現(xiàn)特殊情況
9.6 ReplaceConditionalwithPolymorphism(以多態(tài)取代條件表達(dá)式)255
- 情形:存在條件表達(dá)式根據(jù)對(duì)象的類型不同選擇不同的行為
- 做法:將表達(dá)式分支放進(jìn)不同子類的重寫方法,將原始函數(shù)提煉為抽象函數(shù)幼衰。
9.7 IntroduceNullObject(引入Null對(duì)象)260
- 情形:需要再三檢查對(duì)象是否為null
- 做法:將null值替代為null對(duì)象
9.8 IntroduceAssertion(引入斷言)267
- 情形:某段代碼需要對(duì)程序狀態(tài)做出某種假設(shè)
- 做法:以斷言明確表現(xiàn)這種假設(shè)
- 具體做法:
- 斷言在 發(fā)布的時(shí)候統(tǒng)統(tǒng) 被去除
- 斷言應(yīng)該檢查 ***一定必須為真 *** 的條件
第10章 簡(jiǎn)化函數(shù)調(diào)用271
10.1 RenameMethod(函數(shù)改名)273
- 情形:命名不好
- 做法:
- 增加函數(shù)靴跛,將舊函數(shù)代碼復(fù)制到新函數(shù)
- 修改舊函數(shù),讓其轉(zhuǎn)發(fā)調(diào)用新函數(shù)塑顺,如果舊函數(shù)引用點(diǎn)少可跳過(guò)
- 編譯測(cè)試
- 找出舊函數(shù)引用汤求,調(diào)用新函數(shù)
- 編譯測(cè)試
- 刪除舊函數(shù)
10.2 AddParameter(添加參數(shù))275
- 情形:某個(gè)函數(shù)需要調(diào)用端更多的信息
- 做法:為此函數(shù)添加對(duì)象參數(shù),讓該對(duì)象帶進(jìn)函數(shù)所需信息严拒。
- 其他考慮:
- 現(xiàn)有參數(shù)是否提供足夠的信息扬绪?
- 這個(gè)函數(shù)是否應(yīng)該移動(dòng)到擁有該信息的對(duì)象中?
- 加入新參數(shù)是否合適裤唠,是否需要使用IntroduceParameterObject(引入?yún)?shù)對(duì)象)
10.3 RemoveParameter(移除參數(shù))277
- 情形:函數(shù)不需要某個(gè)參數(shù)
- 做法:將該參數(shù)移除
- 具體做法同10.1
10.4 SeparateQueryfromModifier(將查詢函數(shù)和修改函數(shù)分離)279
- 情形:某個(gè)函數(shù)既返回對(duì)象狀態(tài)值挤牛,又修改對(duì)象狀態(tài)
- 做法:建立兩個(gè)不同的函數(shù),其中一個(gè)負(fù)責(zé)查詢种蘸,另一個(gè)負(fù)責(zé)修改墓赴。
- 原則:任何一個(gè)有返回值的函數(shù)都不應(yīng)該有副作用。
- 多線程:將修改和查詢函數(shù)封裝在一個(gè)同步函數(shù)中分開(kāi)調(diào)用航瞭。
10.5 ParameterizeMethod(令函數(shù)攜帶參數(shù))283
- 情形:若干個(gè)函數(shù)做了類似的工作诫硕,但在函數(shù)本體中卻包含了不同的值。
- 做法:建立單一函數(shù)刊侯,以參數(shù)表達(dá)那些不同的值章办。
- 要點(diǎn): 可將少量數(shù)值視為參數(shù)
10.6 ReplaceParameterwithExplicitMethods(以明確函數(shù)取代參數(shù))285
- 情形:有個(gè)函數(shù)完全有數(shù)值不同采取不同的行為
- 做法:針對(duì)該參數(shù)的每個(gè)可能值,建立獨(dú)立函數(shù)滨彻。
- 對(duì)比:與ParameterizeMethod(令函數(shù)攜帶參數(shù))相反
- 目的:提供清晰的入口藕届。
- 如果參數(shù)值對(duì)函數(shù)行為影響不大,不應(yīng)該采用此方法亭饵。
10.7 PreserveWholeObject(保持對(duì)象完整)288
- 情形:從某個(gè)對(duì)象取若干值休偶,把他們作為參數(shù)傳給函數(shù)
- 做法:改為調(diào)用整個(gè)對(duì)象
- 目的:避免過(guò)長(zhǎng)參數(shù)
- 不使用該方法:
- 如果函數(shù)只依賴那些值不依賴對(duì)象,那么不能采用此方法辜羊,會(huì)導(dǎo)致耦合
- 有時(shí)候函數(shù)使用了很多來(lái)自對(duì)象的數(shù)據(jù)踏兜,那么應(yīng)該考慮使用(Move Method)
10.8 ReplaceParameterwithMethods(以函數(shù)取代參數(shù))292
- 情形:對(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 IntroduceParameterObject(引入?yún)?shù)對(duì)象)295
- 情形:有些參數(shù)總是自然地同時(shí)出現(xiàn)
- 做法:以一個(gè)對(duì)象取代這些參數(shù)
- 目的:縮短參數(shù)長(zhǎng)度,函數(shù)具有一致性喜德,降低理解和修改代碼的難度
10.10 RemoveSettingMethod(移除設(shè)值函數(shù))300
- 情形:類的某個(gè)字段應(yīng)該對(duì)象創(chuàng)建的時(shí)候被設(shè)置,然后不再改變
- 做法:去掉該字段的設(shè)置函數(shù)
10.11 HideMethod(隱藏函數(shù))303
- 情形:有一個(gè)函數(shù)垮媒,從來(lái)沒(méi)有被任何類調(diào)用
- 做法:將該函數(shù)設(shè)為private
10.12 ReplaceConstructorwithFactoryMethod(以工廠函數(shù)取代構(gòu)造函數(shù))304
- 情形:創(chuàng)建對(duì)象時(shí)不僅僅是做簡(jiǎn)單的構(gòu)建動(dòng)作
- 做法:將構(gòu)造函數(shù)替換為工廠模式
10.13 EncapsulateDowncast(封裝向下轉(zhuǎn)型)308
- 情形:某個(gè)函數(shù)返回的對(duì)象舍悯,需要由函數(shù)調(diào)用者執(zhí)行向下轉(zhuǎn)型()downcast
- 做法:將向下轉(zhuǎn)型移到函數(shù)中
10.14 ReplaceErrorCodewithException(以異常取代錯(cuò)誤碼)310
- 情形:某個(gè)函數(shù)返回一個(gè)特定的代碼航棱,表示某個(gè)錯(cuò)誤的情況
- 做法:改用異常
10.15 ReplaceExceptionwithTest(以測(cè)試取代異常)315
- 情形:面對(duì)一個(gè)調(diào)用者可以預(yù)先檢查條件,你拋出了一個(gè)異常
- 做法:修改調(diào)用者萌衬,使它在調(diào)用函數(shù)之前檢查饮醇。
第11章 處理概括關(guān)系319
11.1 PullUpField(字段上移)320
- 情形:兩個(gè)子類擁有相同的字段
- 做法:將該字段移動(dòng)到超類,去除重復(fù)數(shù)據(jù)聲明和關(guān)于數(shù)據(jù)的重復(fù)行為秕豫。并堆超類該字段使用-SelfEncapsulateField(自封裝字段)
11.2 PullUpMethod(函數(shù)上移)322
- 情形:有些函數(shù)朴艰,在各個(gè)子類產(chǎn)生相同的結(jié)果。
- 做法:將該函數(shù)移動(dòng)到超類
11.3 PullUpConstructorBody(構(gòu)造函數(shù)本體上移)325
- 情形:你在各個(gè)子類擁有一些構(gòu)造函數(shù)混移,它們的本地幾乎完全一致
- 做法:在超類新建一個(gè)構(gòu)造函數(shù)祠墅,并在子類構(gòu)造函數(shù)中調(diào)用它。
- 具體做法:
- 將共同代碼復(fù)制到超類構(gòu)造函數(shù)中
- 將共同代碼放在子類構(gòu)造函數(shù)起始處歌径,然后再?gòu)?fù)制到超類構(gòu)造函數(shù)中毁嗦。
- 將子類構(gòu)造函數(shù)中共同代碼刪除,改用調(diào)用新建的超類構(gòu)造函數(shù)回铛。
11.4 PushDownMethod(函數(shù)下移)328
- 情形:超類中的某個(gè)函數(shù)只與部分而非全部子類有關(guān)
- 做法:將這個(gè)函數(shù)移到相關(guān)的子類去狗准。
11.5 PushDownField(字段下移)329
- 情形:超類中的某個(gè)字段只被部分而非全部子類使用
- 做法:將這個(gè)字段移到需要它的那些子類去。
11.6 ExtractSubclass(提煉子類)330
- 情形:類中的某些特性只被某些而非全部實(shí)例用到茵肃。
- 做法:新建一個(gè)子類腔长,將上面所說(shuō)的那一部分特性移到子類中。
- 具體情況:
- 并不是出現(xiàn)類型碼就表示需要用到子類验残,可以在委托和繼承之間做選擇捞附。
- 為子類新建構(gòu)造函數(shù),如果需要 隱藏子類胚膊,可使用ReplaceConstructorwithFactoryMethod(以工廠函數(shù)取代構(gòu)造函數(shù))
- 找出超類調(diào)用點(diǎn)故俐,如超類構(gòu)造函數(shù)與子類不同,通過(guò)rename method方法可以解決紊婉。
- 如果不需要超類實(shí)例药版,可以將超類聲明為抽象類。
- 逐一使用字段下移喻犁、函數(shù)下移將源類的特性移動(dòng)到子類槽片。
11.7 ExtractSuperclass(提煉超類)336
- 情形:兩個(gè)類有相似特性。
- 做法:為兩個(gè)類建立一個(gè)超類肢础,將相同特性移至超類还栓。
11.8 Extract Interface(提煉接口)341
- 情形:某組用戶只使用類責(zé)任區(qū)中一個(gè)特定子集或者兩個(gè)類的接口有部分相同。
- 做法:將相同子集提煉到獨(dú)立的接口中传轰。
- 區(qū)別:提煉超類是提煉共同代碼剩盒,提煉接口時(shí)提煉共同接口。
- 具體情形:如果某個(gè)類在不同環(huán)境下扮演截然不同的角色慨蛙,使用接口就是個(gè)好主意辽聊。
11.9 Collapse Hierarchy(折疊繼承體系)344
- 情形:超類和子類之間區(qū)別不大纪挎。
- 做法:將它們合為一體。
11.10 Form TemPlate Method(塑造模板函數(shù))344
- 情形:你有一些子類跟匆,其中相應(yīng)的函數(shù)以相同順序執(zhí)行類似的操作异袄,但各個(gè)操作的細(xì)節(jié)有所不同。
- 做法:將這些小操作分別放進(jìn)獨(dú)立函數(shù)中玛臂,并保持它們都有相同的簽名烤蜕,于是原函數(shù)也變得相同了。然后將原函數(shù)上移至超類迹冤,運(yùn)用多態(tài)來(lái)避免重復(fù)代碼澡绩。
- 原因:雖然使用了繼承娘香,但是函數(shù)重復(fù)應(yīng)盡量避免。
11.11 Replace inherited with Delegation(以委托取代繼承)352
- 情形:某個(gè)子類只使用超類接口中一部分,或是根本不需要繼承而來(lái)的數(shù)據(jù)
- 做法:在子類中新建一個(gè)字段用以保存超類诫舅,調(diào)整子類函數(shù)兢仰,令它委托超類匠璧,然后去掉兩者之間的繼承關(guān)系芽狗。
11.12 Replace Delegation with Inherited(以繼承取代委托)352
- 情形:在兩個(gè)類之間使用委托關(guān)系,并經(jīng)常為整個(gè)接口編寫許多極簡(jiǎn)單的委托函數(shù)庶橱,
- 做法:讓委托類繼承受托類贮勃。
- 告誡:
- 如果并沒(méi)有使用受托類的所有函數(shù),那么就不要使用這個(gè)方法苏章。因?yàn)樽宇悜?yīng)該總是遵循超類的接口寂嘉,如果委托過(guò)多可以通過(guò)移除“中間人”方法讓客戶端調(diào)用受托函數(shù),或者“提煉超類”枫绅,讓兩個(gè)類的接口提煉到超類中泉孩。類似的還可以使用“提煉接口”方法。
- 如果受托對(duì)象被不止一個(gè)其他對(duì)象共享并淋,而且受托對(duì)象是可變的時(shí)候寓搬,那么這濕乎乎不能講委托關(guān)系替換為繼承關(guān)系。
……