讀《重構(gòu):改善既有代碼的設(shè)計(jì)》

一個(gè)項(xiàng)目運(yùn)行久了蹲堂,經(jīng)過(guò)業(yè)務(wù)需求的迭代赞警,開(kāi)發(fā)人員的變更,總會(huì)產(chǎn)生一些質(zhì)量不高的代碼癣猾,要么來(lái)源于對(duì)某些業(yè)務(wù)理解的不太深梧乘,要么來(lái)源于對(duì)一些緊急變更的后遺癥,往往遇到這種情況稼虎,我們會(huì)適時(shí)的引入重構(gòu),避免破窗效應(yīng)哀军,讓一個(gè)項(xiàng)目越來(lái)越雜亂计济。

重構(gòu)其實(shí)不僅可以重新梳理下我們的業(yè)務(wù)場(chǎng)景排苍,梳理我們代碼的邏輯学密,讓其更貼合業(yè)務(wù)淘衙,更重要的是可以讓開(kāi)發(fā)人員有機(jī)會(huì)再次設(shè)計(jì)我們的系統(tǒng)彤守,結(jié)合一些更好的開(kāi)源項(xiàng)目和技術(shù),提升團(tuán)隊(duì)的技術(shù)氛圍哭靖。

每一次重構(gòu)其實(shí)對(duì)于一個(gè)項(xiàng)目來(lái)說(shuō)都是無(wú)比艱難的決定,上有新業(yè)務(wù)的需求试幽,下有重構(gòu)的使命,時(shí)間緊迫铺坞,希望得到很好的效果,壓力都會(huì)比較大坯沪。但是就是這種環(huán)境很容易鍛煉人,使人飛速成長(zhǎng)腐晾,通力合作,團(tuán)隊(duì)也會(huì)得到很好的磨練藻糖。

  1. 首先我們考慮先要梳理項(xiàng)目的痛點(diǎn),重構(gòu)其實(shí)更重要是解決現(xiàn)在的實(shí)際問(wèn)題颖御。
  2. 提出更高要求凝颇,例如提高項(xiàng)目承載能力,應(yīng)對(duì)更大業(yè)務(wù)需求拧略。

什么是重構(gòu)?

  • 是在不改變系統(tǒng)行為的前提下禽最,對(duì)內(nèi)部代碼的重新組織腺怯,提高可理解性和降低修改成本川无。

為什么要重構(gòu)?

  • 一個(gè)小修改牽涉到了多個(gè)地方懦趋,且這些點(diǎn)處于未知狀態(tài)
  • 不易讀懂代碼(包括讀懂自己1個(gè)月前的代碼)
  • 新手修改代碼上手慢,需要很久才能進(jìn)行有信心的代碼修改
  • 需求變化時(shí)帜篇,代碼層面響應(yīng)慢

什么時(shí)候需要重構(gòu)?

  • 隨時(shí)隨地的重構(gòu)诫咱,也就是從一開(kāi)始就進(jìn)行小范圍的重構(gòu),就不至于時(shí)間久后沒(méi)法平滑的重構(gòu)了
  • 上面這句實(shí)際上是個(gè)方法論級(jí)別的竟痰,真實(shí)中,還是沒(méi)辦法判斷什么時(shí)候要進(jìn)行重構(gòu)凯亮,于是換成:當(dāng)代碼中出現(xiàn)了壞味道時(shí)需要重構(gòu)
  • 什么是壞味道:
    • 存在重復(fù)代碼時(shí)
    • 函數(shù)體太長(zhǎng)
    • 函數(shù)參數(shù)太長(zhǎng)
    • 無(wú)法直觀的看出代碼邏輯
    • 類太大
    • 對(duì)一個(gè)常量存在了多個(gè)副本
    • 很多很多的if/else/switch語(yǔ)句
    • 類名哄尔、函數(shù)名、方法名不友好

重構(gòu)與性能

  • 重構(gòu)為先岭接,調(diào)優(yōu)其次
  • 重構(gòu)能組織良好的結(jié)構(gòu),良好的結(jié)構(gòu)能讓調(diào)優(yōu)工作更輕松

重新組織函數(shù)

  • Extract Method(提煉函數(shù))
    • 當(dāng)內(nèi)部邏輯過(guò)分纏繞在一起時(shí)鸣戴,需要將一些代碼抽取到子函數(shù)中
  • Inline Method(內(nèi)聯(lián)函數(shù))
    • 如果一個(gè)函數(shù)體很少,并且沒(méi)有被其他函數(shù)使用到创千,就可以考慮將這個(gè)小函數(shù)內(nèi)聯(lián)到父函數(shù)中
  • Inline Temp(內(nèi)聯(lián)臨時(shí)變量)
    • 如果一個(gè)變量只被使用到了1次入偷,并且這個(gè)變量所代表的邏輯很少,此時(shí)可以考慮將這個(gè)臨時(shí)變量所代表的邏輯直接拷貝到父函數(shù)中
  • Replace Temp with Query(以查詢?nèi)〈R時(shí)變量)
    • 如果去除了臨時(shí)變量后疏之,更加利于后續(xù)的重構(gòu)改動(dòng),則會(huì)使用這種方法丙曙,將臨時(shí)變量所代表的邏輯抽取成單獨(dú)一個(gè)函數(shù)
    • 雖然對(duì)性能有影響爸业,但是重構(gòu)過(guò)去后,如果不是很嚴(yán)重的性能影響亏镰,則還是建議改成這樣扯旷,因?yàn)橹貥?gòu)過(guò)去后對(duì)后續(xù)重構(gòu)更有利,更便于以后的重構(gòu)
  • Introduce Explaining Variable(引入解釋性變量)
    • 將邏輯碎片賦給命名友好的變量名索抓,這樣代碼的可讀性钧忽、理解性更強(qiáng)
  • Split Temporary variable(分解臨時(shí)變量)
    • 一個(gè)邏輯目的只賦給一個(gè)臨時(shí)變量,不要合用臨時(shí)變量纸兔,如:
int temp=x+y;
//some logic to process temp varialbe
temp=getBase()+100;
//some logic to process the new temp varialbe
  • Remove Assignments to Parameters(移除對(duì)參數(shù)的賦值)
    • 禁止對(duì)傳入?yún)?shù)的賦值,要用增加臨時(shí)變量的方式來(lái)
  • Replace Method with method Object(以函數(shù)對(duì)象取代函數(shù))
    • 針對(duì)大函數(shù)否副、邏輯復(fù)雜汉矿、局部變量多時(shí)
    • 思想是將這個(gè)函數(shù)獨(dú)立成為一個(gè)類,在類中進(jìn)行復(fù)雜邏輯的處理
  • Substitute Algorithm(替換算法)
    • 將函數(shù)內(nèi)部的算法替換掉备禀,比如:為了更高的效率或者更好的可理解性
    • 意圖是提升效率或者可理解性
  • 大方向上都是讓語(yǔ)義更加清晰

在對(duì)象之間搬移特性

  • Move Method(搬移函數(shù))
    • 如果發(fā)現(xiàn)某個(gè)函數(shù)主要依賴于其他類的數(shù)據(jù)洲拇,則有必要將這個(gè)函數(shù)move到那個(gè)類中
  • Move Field(搬移字段)
    • 和上面的類似,至于是用哪個(gè)方法重構(gòu)曲尸,需要看情況赋续,比如看類的名稱纽乱、職責(zé)定義
  • Extract Class(提煉類)
    • 當(dāng)類包含大量函數(shù)昆箕、數(shù)據(jù)時(shí),需要考慮拆分類
  • Inline Class(將類內(nèi)聯(lián)化)
    • 當(dāng)某個(gè)類的職責(zé)不足以成為一個(gè)類時(shí)薯嗤,考慮將這個(gè)類合并到其他類中
    • 比如這種情況發(fā)生在重構(gòu)行為后纤泵,弱化了某個(gè)類的職責(zé)
  • Hide Delegate(隱藏“委托關(guān)系”)
    • 在server端隱藏某個(gè)類捏题,這樣客戶端只需要知道1個(gè)類就能做邏輯操作,而不需要同時(shí)知道多個(gè)類才能進(jìn)行邏輯操作了
  • Remove Middle Man(移除中間人)
    • 暴露更多的類來(lái)供客戶端調(diào)用
    • “中間人”的移除與否比較難定公荧,一般模塊之間是盡量少暴露稚矿,模塊內(nèi)部要看情況而定
  • Introduce Foreign Method(引入外加函數(shù))
    • 當(dāng)提供的函數(shù)不能修改時(shí)捻浦,可以在客戶端增加一個(gè)函數(shù)來(lái)包裝這個(gè)目標(biāo)函數(shù)朱灿,完成額外邏輯的插入轉(zhuǎn)換
    • 這種額外函數(shù)不多
    • 用多了不好钠四,最終需要合并到目標(biāo)函數(shù)所在的server端
  • Introduce Local Extension(引入本地?cái)U(kuò)展)
    • 如果發(fā)生上述情況,并且擴(kuò)展的比較多侣灶,則可以在客戶端新建一個(gè)類褥影,通過(guò)繼承或者Wrapper的方式導(dǎo)入原始方法或類咏雌,進(jìn)行額外方法、函數(shù)统倒、邏輯的加工

重新組織數(shù)據(jù)

  • Self Encapsulate Field(自封裝字段)
    • C#中使用屬性來(lái)解決氛雪,不引用字段报亩,要引用屬性,以便在需要覆寫(xiě)變量值的時(shí)候嵌入邏輯
  • Replace Data Value with Object(以對(duì)象取代數(shù)據(jù)值)
    • 當(dāng)對(duì)某個(gè)基元數(shù)據(jù)有更多的普遍常用功能時(shí)捆昏,需要將基元數(shù)據(jù)替換為對(duì)象類型骗卜,進(jìn)而在這個(gè)對(duì)象中實(shí)現(xiàn)一些常用功能,方便調(diào)用方的調(diào)用
  • Change Value to Reference(將值對(duì)象改為引用對(duì)象)
    • 如果當(dāng)前的某個(gè)值對(duì)象被多個(gè)地方用到举户,并且此時(shí)希望更改了一處后遍烦,其他地方的引用也跟著改變服猪,此時(shí)需要將這個(gè)值對(duì)象轉(zhuǎn)換為引用對(duì)象
    • 場(chǎng)景:項(xiàng)目剛開(kāi)始時(shí)用了值對(duì)象拐云,但是后來(lái)認(rèn)為用引用類型更好叉瘩,此時(shí)就需要轉(zhuǎn)換
  • Change Reference to Value(將引用對(duì)象改為值對(duì)象)
    • 如果存在一個(gè)引用類型薇缅,而且這個(gè)引用類型較小,且不需要實(shí)現(xiàn)實(shí)例間的互相更改泳桦,此時(shí)可以把這個(gè)引用類型改為值類型灸撰,這樣能保證這個(gè)對(duì)象的不可變性
  • Replace Array with Object(以對(duì)象取代數(shù)組)
    • 當(dāng)一個(gè)數(shù)組被用在了傳遞對(duì)象屬性用途時(shí)漆羔,可以采用類來(lái)替代這個(gè)數(shù)組
  • Duplicate Observed Data(復(fù)制“被監(jiān)視的數(shù)據(jù)”)
    • 層與層之間的纏繞調(diào)用狱掂,沒(méi)有劃分好層導(dǎo)致的
    • 層與層之間通過(guò)DTO的方式進(jìn)行傳輸數(shù)據(jù)
  • Change Unidirectional Association to Bidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))
    • 謹(jǐn)慎使用趋惨,盡量使單向關(guān)聯(lián)
    • 需要在雙方對(duì)象中加入維護(hù)對(duì)方的代碼,如:Customer.AddOrder/Order.AddCustomer讯嫂,都要成對(duì)出現(xiàn)
  • Change Bidirectional Association to Unidirectional(將雙向關(guān)聯(lián)改為單向關(guān)聯(lián))
    • 隨著需求的演化兆沙,在某時(shí)間段,發(fā)現(xiàn)不需要雙向關(guān)聯(lián)了千扔,此時(shí)用此法
  • Replace Magic Number with Symbolic Constant(以字面常量取代魔法數(shù))
    • 字面量需要用const常量來(lái)替代
    • 如科學(xué)計(jì)算中某些具有特殊意義的數(shù)值库正,需要統(tǒng)一const引用
  • Encapsulate Field(封裝字段)
    • 數(shù)據(jù)和行為被分開(kāi)后褥符,由于誰(shuí)都可以引用public數(shù)據(jù),因此不容易管理及修改
    • 如果不暴露數(shù)據(jù)趟大,這樣就能做到只在當(dāng)前class中使用這些數(shù)據(jù)了
  • Encapsulate Collection(封裝集合)
    • 默認(rèn)的List<T> Collection<T> ArrayList暴露了太多內(nèi)部邏輯,而且返回的對(duì)象能夠被客戶端修改魂迄,不利于隔離與封裝
    • 自己寫(xiě)集合類惋耙,可以只暴露特定接口、返回對(duì)象新的拷貝绽榛,這樣能解決惡意、無(wú)意的修改
  • Replace Record with Data Class(以數(shù)據(jù)類取代記錄)
    • 將非對(duì)象化的平面數(shù)據(jù)類型(如:數(shù)組推溃、傳遞過(guò)來(lái)的沒(méi)有良好命名的屬性等)铁坎,重寫(xiě)成class犁苏,只有private屬性的class
    • 目的只是為以后更進(jìn)一步的重構(gòu)做準(zhǔn)備
  • Replace Type Code with Class(以類取代類型碼)
    • Type Code:枚舉、多個(gè)string朴乖、int變量买羞,如:string Male="男性" string Female="女性")畜普,諸如此類的標(biāo)識(shí)
    • 將這個(gè)Type Code(包含了多個(gè)字段群叶,但是只是區(qū)分不同的Type)抽象為一個(gè)Type Code類
    • 引用的相關(guān)地方也要做出更改
  • Replace Type Code with Subclasses(以子類取代類型碼)
    • 用子類來(lái)標(biāo)識(shí),這樣可以使用重寫(xiě)函數(shù)來(lái)解決一些行為上的變化
  • Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
    • 用狀態(tài)儒鹿、策略模式將變化部分抽取出來(lái)
  • Replace Subclass with Fields(以字段取代子類)
    • 如果子類中只是簡(jiǎn)單的返回一些常量约炎,則可以將這些子類廢除,壓縮繼承級(jí)別掠手,將類型判斷的邏輯寫(xiě)在父類的相應(yīng)方法中

簡(jiǎn)化條件表達(dá)式

  • Decompose Conditional(分解條件表達(dá)式)
    • 往往邏輯比較復(fù)雜的地方狸捕,分支就較多
    • 一個(gè)分支中如果寫(xiě)了很多小段代碼灸拍,也應(yīng)該重構(gòu)成更有語(yǔ)義的代碼
    • 需要將分支重構(gòu)為更加語(yǔ)義化,這樣會(huì)提高可讀性
  • Consolidate Conditional Expression(合并條件表達(dá)式)
    • 一般在函數(shù)入口出會(huì)檢查參數(shù)有效性混槐,如果寫(xiě)有多條if語(yǔ)句判斷為無(wú)效轩性,都返回false,則可以將這些都return false的判斷抽取到一個(gè)單獨(dú)函數(shù)中
    • 主函數(shù)中語(yǔ)義更加清晰
  • Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片段)
    • 如果在if/else分支中揣苏,每個(gè)分支的開(kāi)始或者結(jié)束區(qū)域都使用了同樣的代碼,則提取到if/else外進(jìn)行統(tǒng)一調(diào)用
  • Remove Control Flag(移除控制標(biāo)記)
    • 用在循環(huán)中脯厨,去掉控制標(biāo)記俄认,比如bool found=false之類的控制標(biāo)記洪乍,當(dāng)找到時(shí)夜焦,直接return obj/return;
  • Replace Nested Conditional with Guard Clauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)
    • 把if/else以及嵌套的if/else改成平面寫(xiě)法,如:
if(xxx)return result+1;
if(yyy)return result+2;
if(zzz)return result+3;
return result+4;
  • Replace Conditional with Polymorphism(以多態(tài)取代條件表達(dá)式)
    • 用在有多個(gè)子類的繼承體系中巷波,父類有個(gè)方法用來(lái)計(jì)算:根據(jù)不同的子類來(lái)計(jì)算不同的value
    • 套用模板方法設(shè)計(jì)模式一樣
  • Introduce Null Object(引入Null對(duì)象)
    • 針對(duì)null對(duì)象的設(shè)計(jì)模式
    • 可以將null時(shí)抹镊,業(yè)務(wù)邏輯的例外算法在NullObject中實(shí)現(xiàn)一份荤傲,這樣在業(yè)務(wù)邏輯類中就不需要些一堆if null之類的判斷以及轉(zhuǎn)發(fā)了
  • Introduce Assertion(引入斷言)
    • 在函數(shù)的入口編寫(xiě)Assert,用來(lái)確保被調(diào)用此函數(shù)時(shí)俊嗽,相應(yīng)的前置條件是否正確铃彰,使用
    • 如果斷言失敗牙捉,則會(huì)在日志文件中出現(xiàn)調(diào)用堆棧信息以及自定義信息
    • System.Diagnostics.Trace.Assert:無(wú)論是否Release,都會(huì)記錄日志
    • System.Diagnostics.Trace.Debug:只在Debug模式下生成日志信息

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

  • Rename Method(函數(shù)改名)
  • 修改函數(shù)命名為更有語(yǔ)義鬼佣,提高可讀性
    • 參數(shù)順序霜浴、參數(shù)命名也是考慮之一
  • Add Parameter(添加參數(shù))
    • 修改了一個(gè)函數(shù)阴孟,但是這個(gè)函數(shù)目前又需要用到以前所沒(méi)有的信息
  • Remove Parameter(移除參數(shù))
    • 以前的參數(shù)永丝,現(xiàn)在不需要了
  • Separate Query from Modifier(將查詢函數(shù)和修改函數(shù)分離)
    • 如果一個(gè)函數(shù)在返回值的過(guò)程中,也去修改了一些值哥牍,則會(huì)對(duì)客戶端調(diào)用者產(chǎn)生某些困擾嗅辣,需要將其拆分為2個(gè)函數(shù):Query澡谭、Modify
  • Parameterize Method(令函數(shù)攜帶參數(shù))
    • 在函數(shù)內(nèi)部提取公用子函數(shù)损俭,來(lái)實(shí)現(xiàn)代碼的扁平化及公用化
  • Replace Parameter with Explicit Methods(以明確函數(shù)取代參數(shù))
    • 當(dāng)函數(shù)行為完全取決于參數(shù)value時(shí)杆兵,需要將這個(gè)函數(shù)拆分到多個(gè)方法,避免函數(shù)內(nèi)部邏輯太雜
  • Reserve Whole Object(保持對(duì)象完整)
    • 當(dāng)被調(diào)用函數(shù)的參數(shù)正好是某對(duì)象的其中幾個(gè)屬性時(shí)攒砖,則直接傳入這個(gè)對(duì)象
    • 需要同時(shí)考慮被調(diào)用函數(shù)是否需要move到這個(gè)對(duì)象中
  • Replace Parameter with Methods(以函數(shù)取代參數(shù))
    • 如果主函數(shù)中包含有多個(gè)子函數(shù)祭衩,并且這些子函數(shù)返回值只是首尾傳入傳出
    • 此時(shí)掐暮,考慮將除最后一個(gè)函數(shù)外,其他子函數(shù)不通過(guò)主函數(shù)來(lái)調(diào)用樟结,而是通過(guò)最后一個(gè)字函數(shù)的內(nèi)部進(jìn)行調(diào)用
  • Introduce Parameter Object(引入?yún)?shù)對(duì)象)
    • 當(dāng)某些參數(shù)總是成對(duì)瓢宦、成堆出現(xiàn)時(shí)驮履,考慮此模式
      如:
DateTime from, DateTime end==> DateRange
int pageIndex, int pageSize==>PagingInfo
以及PagingResult<T>{TotalCount, List<T>}
  • Remove Setting Method(移除設(shè)值函數(shù))
    • 如果某個(gè)類的屬性在構(gòu)造后就不需要被改變玫镐,則把相應(yīng)的set訪問(wèn)器關(guān)閉
  • Hide Method(隱藏函數(shù))
    • 如果某函數(shù)沒(méi)有被其他類引用到恐似,就改成private的
  • Replace Constructor with Factory Method(以工廠函數(shù)取代構(gòu)造函數(shù))
    • 當(dāng)類存在多個(gè)子類傍念,并且希望通過(guò)類型碼來(lái)生成新對(duì)象時(shí)憋槐,可以將構(gòu)造函數(shù)改成工廠方法,這樣便于客戶端調(diào)用蔓彩,無(wú)需知道到底是哪個(gè)子類
  • Encapsulate Downcast(封裝向下轉(zhuǎn)型)
    • 是說(shuō)對(duì)于類型的強(qiáng)制轉(zhuǎn)換驳概,需要放在具體的函數(shù)中實(shí)現(xiàn)顺又,不要放在客戶端代碼中
    • 現(xiàn)在.Net有了泛型稚照,減少了很多這種麻煩
  • Replace Error Code with Exception(以異常取代錯(cuò)誤碼)
    • 在代碼中如遇異常果录,則直接throw new XXXXException("xx")弱恒,而不是用return errorCode的方式
    • 如果是可控異常,則在catch(XXXException ex)處理掉
    • 如果是不可控異常锈玉,則無(wú)需處理
    • 不可控異常應(yīng)有框架來(lái)處理拉背,如AOP或者Global中的Error事件
  • Replace Exception with Test(以測(cè)試取代異常)
    • 對(duì)于濫用了catch異常的邏輯進(jìn)行邏輯上的修改
    • 用單元測(cè)試+Assert+邊界值測(cè)試來(lái)確保某些異常沒(méi)有被觸發(fā)

處理概括關(guān)系

  • Pull Up Field(字段上移)
    • 當(dāng)多個(gè)子類中存在相似的字段時(shí)椅棺,需要分析下是否需要將這些相似的字段提取到父類中
  • Pull Up Method(函數(shù)上移)
    • 當(dāng)多個(gè)子類中存在相似的函數(shù)時(shí)土陪,需要分析下是否需要將這些相似的函數(shù)提取到父類中
    • 如果完全相同肴熏,那就直接提取到父類
    • 如果只是某個(gè)步驟不通蛙吏,則通過(guò)模板方法把公用邏輯提升到父類中
  • Pull Up Constructor Body(構(gòu)造函數(shù)本體上移)
    • 子類中的構(gòu)造函數(shù)盡量利用父類的構(gòu)造函數(shù)來(lái)賦值
  • Pull Down Method(函數(shù)下移)
    • 當(dāng)父類中的某個(gè)函數(shù)只與某幾個(gè)子類(非全部)有關(guān)時(shí)鸦做,則將這個(gè)函數(shù)下放到具體的子類中實(shí)現(xiàn)
  • Pull Down Field(字段下移)
    • 當(dāng)父類中的某個(gè)字段只與某幾個(gè)子類(非全部)有關(guān)時(shí),則將這個(gè)字段下放到具體的子類中
  • Extract Subclass(提煉子類)
    • 當(dāng)存在Type Code時(shí)坛掠,或者當(dāng)類的某些instance存在不一樣的行為時(shí)屉栓,需要提煉子類
    • 類的某些特性只被某些instance用到
  • Extract Superclass(提煉超類)
    • 如果多個(gè)類之間存在相似的特性友多,則可以新增一個(gè)超類將共性提取出來(lái)
  • Extract Interface(提煉接口)
    • 直接引用一個(gè)類域滥,會(huì)將所有的方法暴露出來(lái)
    • 如果根據(jù)職責(zé)定義接口,再讓類實(shí)現(xiàn)這些接口昂儒,調(diào)用時(shí)的封裝委可、隱蔽性就會(huì)好很多
  • Collapse Hierarchy(折疊繼承體系)
    • 當(dāng)父類與子類之間的區(qū)別不大時(shí)撤缴,可以將它們合并,去掉層級(jí)關(guān)系
  • Form Template Method(塑造模板函數(shù))
    • 其實(shí)就是模板設(shè)計(jì)模式的應(yīng)用
  • Replace Inheritance with Delegation(以委托取代繼承)
    • 當(dāng)子類發(fā)現(xiàn)實(shí)際不需要使用集成來(lái)的數(shù)據(jù)微宝、函數(shù)時(shí)蟋软,或者只用到了少數(shù)父類的數(shù)據(jù)岳守、函數(shù)時(shí)碌冶,則可以去掉繼承關(guān)系扑庞,在當(dāng)前類中加上父類引用罐氨,通過(guò)委托方式來(lái)調(diào)用父類的數(shù)據(jù)、功能
  • Replace Delegation with Inheritance(以繼承取代委托)
    • 當(dāng)2個(gè)類之間使用了很多委托來(lái)進(jìn)行調(diào)用塔嬉,并且這些委托覆蓋面為對(duì)方的大范圍時(shí)谨究,考慮將委托改成繼承關(guān)系

大型重構(gòu)

  • Tease Apart Inheritance(梳理并分解繼承體系)
    • 橋接模式的分割
  • Convert Procedural Design to Objects(將過(guò)程化設(shè)計(jì)轉(zhuǎn)化為對(duì)象設(shè)計(jì))
    • OO對(duì)象的建立
    • 職責(zé)的分離
  • Separate Domain from Presentation(將領(lǐng)域和表述/顯示分離)
    • MVC模式
    • MVVM模式
    • View與Domain的區(qū)分
  • Extract Hierarchy(提煉繼承體系)
    • 開(kāi)發(fā)封閉原則
      • 對(duì)擴(kuò)展開(kāi)放记盒,意味著有新的需求或變化時(shí)纪吮,可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展萎胰,以適應(yīng)新的情況技竟。
      • 對(duì)修改封閉,意味著類一旦設(shè)計(jì)完成熙尉,就可以獨(dú)立完成其工作检痰,而不要對(duì)類進(jìn)行任何修改铅歼。

個(gè)人介紹:

高廣超 :多年一線互聯(lián)網(wǎng)研發(fā)與架構(gòu)設(shè)計(jì)經(jīng)驗(yàn)椎椰,擅長(zhǎng)設(shè)計(jì)與落地高可用沾鳄、高性能互聯(lián)網(wǎng)架構(gòu)译荞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末磁椒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子本辐,更是在濱河造成了極大的恐慌慎皱,老刑警劉巖茫多,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件天揖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡些阅,警方通過(guò)查閱死者的電腦和手機(jī)斑唬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門恕刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)褐着,“玉大人,你說(shuō)我怎么就攤上這事洋访∫稣” “怎么了汁展?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵食绿,是天一觀的道長(zhǎng)公罕。 經(jīng)常有香客問(wèn)我楼眷,道長(zhǎng),這世上最難降的妖魔是什么掌腰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任齿梁,我火速辦了婚禮勺择,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扰藕。我一直安慰自己芳撒,他們只是感情好笔刹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布舌菜。 她就那樣靜靜地躺著日月,像睡著了一般缤骨。 火紅的嫁衣襯著肌膚如雪绊起。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天蜂绎,我揣著相機(jī)與錄音师枣,去河邊找鬼践美。 笑死拨脉,一個(gè)胖子當(dāng)著我的面吹牛宣增,可吹牛的內(nèi)容都是我干的爹脾。 我是一名探鬼主播箕昭,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼落竹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼述召!你這毒婦竟也來(lái)了积暖?” 一聲冷哼從身側(cè)響起夺刑,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遍愿,失蹤者是張志新(化名)和其女友劉穎沼填,沒(méi)想到半個(gè)月后煌往,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡羞海,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了院水。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恢恼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漓踢,我是刑警寧澤喧半,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布挺据,位于F島的核電站,受9級(jí)特大地震影響者填,放射性物質(zhì)發(fā)生泄漏做葵。R本人自食惡果不足惜酿矢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一瘫筐、第九天 我趴在偏房一處隱蔽的房頂上張望铐姚。 院中可真熱鬧隐绵,春花似錦、人聲如沸棺禾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拯刁。三九已至,卻和暖如春逸绎,著一層夾襖步出監(jiān)牢的瞬間棺牧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工参淹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浙值,地道東北人开呐。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓筐付,卻偏偏與公主長(zhǎng)得像瓦戚,于是被迫代替她去往敵國(guó)和親丛塌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容