亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

重拾《重構-改善既有代碼的設計》

2019-11-17 01:28:22
字體:
來源:轉載
供稿:網友

重拾《重構-改善既有代碼的設計》

什么是重構?

  • 是在不改變系統行為的前提下,對內部代碼的重新組織,提高可理解性和降低修改成本。

為什么要重構?

  • 一個小修改牽涉到了多個地方,且這些點處于未知狀態
  • 不易讀懂代碼(包括讀懂自己1個月前的代碼)
  • 新手修改代碼上手慢,需要很久才能進行有信心的代碼修改
  • 需求變化時,代碼層面響應慢

什么時候需要重構?

  • 隨時隨地的重構,也就是從一開始就進行小范圍的重構,就不至于時間久后沒法平滑的重構了
  • 上面這句實際上是個方法論級別的,真實中,還是沒辦法判斷什么時候要進行重構,于是換成:當代碼中出現了壞味道時需要重構
  • 什么是壞味道:
    • 存在重復代碼時
    • 函數體太長
    • 函數參數太長
    • 無法直觀的看出代碼邏輯
    • 類太大
    • 對一個常量存在了多個副本
    • 很多很多的if/else/switch語句
    • 類名、函數名、方法名不友好

重構與性能

  • 重構為先,調優其次
  • 重構能組織良好的結構,良好的結構能讓調優工作更輕松

重新組織函數

  • Extract Method(提煉函數)
    • 當內部邏輯過分纏繞在一起時,需要將一些代碼抽取到子函數中
  • Inline Method(內聯函數)
    • 如果一個函數體很少,并且沒有被其他函數使用到,就可以考慮將這個小函數內聯到父函數中
  • Inline Temp(內聯臨時變量)
    • 如果一個變量只被使用到了1次,并且這個變量所代表的邏輯很少,此時可以考慮將這個臨時變量所代表的邏輯直接拷貝到父函數中
  • Replace Temp with Query(以查詢取代臨時變量)
    • 如果去除了臨時變量后,更加利于后續的重構改動,則會使用這種方法,將臨時變量所代表的邏輯抽取成單獨一個函數
    • 雖然對性能有影響,但是重構過去后,如果不是很嚴重的性能影響,則還是建議改成這樣,因為重構過去后對后續重構更有利,更便于以后的重構
  • Introduce Explaining Variable(引入解釋性變量)
    • 將邏輯碎片賦給命名友好的變量名,這樣代碼的可讀性、理解性更強
  • Split Temporary variable(分解臨時變量)
    • 一個邏輯目的只賦給一個臨時變量,不要合用臨時變量,如:
    • 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(移除對參數的賦值)
    • 禁止對傳入參數的賦值,要用增加臨時變量的方式來
  • Replace Method with method Object(以函數對象取代函數)
    • 針對大函數、邏輯復雜、局部變量多時
    • 思想是將這個函數獨立成為一個類,在類中進行復雜邏輯的處理
  • Substitute Algorithm(替換算法)
    • 將函數內部的算法替換掉,比如:為了更高的效率或者更好的可理解性
    • 意圖是提升效率或者可理解性
  • 大方向上都是讓語義更加清晰

在對象之間搬移特性

  • Move Method(搬移函數)
    • 如果發現某個函數主要依賴于其他類的數據,則有必要將這個函數move到那個類中
  • Move Field(搬移字段)
    • 和上面的類似,至于是用哪個方法重構,需要看情況,比如看類的名稱、職責定義
  • Extract Class(提煉類)
    • 當類包含大量函數、數據時,需要考慮拆分類
  • Inline Class(將類內聯化)
    • 當某個類的職責不足以成為一個類時,考慮將這個類合并到其他類中
    • 比如這種情況發生在重構行為后,弱化了某個類的職責
  • Hide Delegate(隱藏“委托關系”)
    • 在server端隱藏某個類,這樣客戶端只需要知道1個類就能做邏輯操作,而不需要同時知道多個類才能進行邏輯操作了
  • Remove Middle Man(移除中間人)
    • 暴露更多的類來供客戶端調用
    • “中間人”的移除與否比較難定,一般模塊之間是盡量少暴露,模塊內部要看情況而定
  • Introduce Foreign Method(引入外加函數)
    • 當提供的函數不能修改時,可以在客戶端增加一個函數來包裝這個目標函數,完成額外邏輯的插入轉換
    • 這種額外函數不多
    • 用多了不好,最終需要合并到目標函數所在的server端
  • Introduce Local Extension(引入本地擴展)
    • 如果發生上述情況,并且擴展的比較多,則可以在客戶端新建一個類,通過繼承或者Wrapper的方式導入原始方法或類,進行額外方法、函數、邏輯的加工

重新組織數據

  • Self Encapsulate Field(自封裝字段)
    • C#中使用屬性來解決,不引用字段,要引用屬性,以便在需要覆寫變量值的時候嵌入邏輯
  • Replace Data Value with Object(以對象取代數據值)
    • 當對某個基元數據有更多的普遍常用功能時,需要將基元數據替換為對象類型,進而在這個對象中實現一些常用功能,方便調用方的調用
  • Change Value to Reference(將值對象改為引用對象)
    • 如果當前的某個值對象被多個地方用到,并且此時希望更改了一處后,其他地方的引用也跟著改變,此時需要將這個值對象轉換為引用對象
    • 場景:項目剛開始時用了值對象,但是后來認為用引用類型更好,此時就需要轉換
  • Change Reference to Value(將引用對象改為值對象)
    • 如果存在一個引用類型,而且這個引用類型較小,且不需要實現實例間的互相更改,此時可以把這個引用類型改為值類型,這樣能保證這個對象的不可變性
  • Replace Array with Object(以對象取代數組)
    • 當一個數組被用在了傳遞對象屬性用途時,可以采用類來替代這個數組
  • Duplicate Observed Data(復制“被監視的數據”)
    • 層與層之間的纏繞調用,沒有劃分好層導致的
    • 層與層之間通過DTO的方式進行傳輸數據
  • Change Unidirectional Association to Bidirectional(將單向關聯改為雙向關聯)
    • 謹慎使用,盡量使單向關聯
    • 需要在雙方對象中加入維護對方的代碼,如:Customer.AddOrder/Order.AddCustomer,都要成對出現
  • Change Bidirectional Association to Unidirectional(將雙向關聯改為單向關聯)
    • 隨著需求的演化,在某時間段,發現不需要雙向關聯了,此時用此法
  • Replace Magic Number with Symbolic Constant(以字面常量取代魔法數)
    • 字面量需要用const常量來替代
    • 如科學計算中某些具有特殊意義的數值,需要統一const引用
  • Encapsulate Field(封裝字段)
    • 數據和行為被分開后,由于誰都可以引用public數據,因此不容易管理及修改
    • 如果不暴露數據,這樣就能做到只在當前class中使用這些數據了
  • Encapsulate Collection(封裝集合)
    • 默認的List<T> Collection<T> ArrayList暴露了太多內部邏輯,而且返回的對象能夠被客戶端修改,不利于隔離與封裝
    • 自己寫集合類,可以只暴露特定接口、返回對象新的拷貝,這樣能解決惡意、無意的修改
  • Replace Record with Data Class(以數據類取代記錄)
    • 將非對象化的平面數據類型(如:數組、傳遞過來的沒有良好命名的屬性等),重寫成class,只有private屬性的class
    • 目的只是為以后更進一步的重構做準備
  • Replace Type Code with Class(以類取代類型碼)
    • Type Code:枚舉、多個string、int變量,如:string Male="男性" string Female="女性"),諸如此類的標識
    • 將這個Type Code(包含了多個字段,但是只是區分不同的Type)抽象為一個Type Code類
    • 引用的相關地方也要做出更改
  • Replace Type Code with Subclasses(以子類取代類型碼)
    • 用子類來標識,這樣可以使用重寫函數來解決一些行為上的變化
  • Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
    • 用狀態、策略模式將變化部分抽取出來
  • Replace Subclass with Fields(以字段取代子類)
    • 如果子類中只是簡單的返回一些常量,則可以將這些子類廢除,壓縮繼承級別,將類型判斷的邏輯寫在父類的相應方法中

簡化條件表達式

  • Decompose Conditional(分解條件表達式)
    • 往往邏輯比較復雜的地方,分支就較多
    • 一個分支中如果寫了很多小段代碼,也應該重構成更有語義的代碼
    • 需要將分支重構為更加語義化,這樣會提高可讀性
  • Consolidate Conditional Expression(合并條件表達式)
    • 一般在函數入口出會檢查參數有效性,如果寫有多條if語句判斷為無效,都返回false,則可以將這些都return false的判斷抽取到一個單獨函數中
    • 主函數中語義更加清晰
  • Consolidate Duplicate Conditional Fragments(合并重復的條件片段)
    • 如果在if/else分支中,每個分支的開始或者結束區域都使用了同樣的代碼,則提取到if/else外進行統一調用
  • Remove Control Flag(移除控制標記)
    • 用在循環中,去掉控制標記,比如bool found=false之類的控制標記,當找到時,直接return obj/return;
  • Replace Nested Conditional with Guard Clauses(以衛語句取代嵌套條件表達式)
    • 把if/else以及嵌套的if/else改成平面寫法,如:
    • if(xxx)return result+1;
    • if(yyy)return result+2;
    • if(zzz)return result+3;
    • return result+4;
  • Replace Conditional with Polymorphism(以多態取代條件表達式)
    • 用在有多個子類的繼承體系中,父類有個方法用來計算:根據不同的子類來計算不同的value
    • 套用模板方法設計模式一樣
  • Introduce Null Object(引入Null對象)
    • 針對null對象的設計模式
    • 可以將null時,業務邏輯的例外算法在NullObject中實現一份,這樣在業務邏輯類中就不需要些一堆if null之類的判斷以及轉發了
  • Introduce Assertion(引入斷言)
    • 在函數的入口編寫Assert,用來確保被調用此函數時,相應的前置條件是否正確,使用
    • 如果斷言失敗,則會在日志文件中出現調用堆棧信息以及自定義信息
    • System.Diagnostics.Trace.Assert:無論是否Release,都會記錄日志
    • System.Diagnostics.Trace.Debug:只在Debug模式下生成日志信息

簡化函數調用

  • Rename Method(函數改名)
    • 修改函數命名為更有語義,提高可讀性
    • 參數順序、參數命名也是考慮之一
  • Add Parameter(添加參數)
    • 修改了一個函數,但是這個函數目前又需要用到以前所沒有的信息
  • Remove Parameter(移除參數)
    • 以前的參數,現在不需要了
  • Separate Query from Modifier(將查詢函數和修改函數分離)
    • 如果一個函數在返回值的過程中,也去修改了一些值,則會對客戶端調用者產生某些困擾,需要將其拆分為2個函數:Query、Modify
  • Parameterize Method(令函數攜帶參數)
    • 在函數內部提取公用子函數,來實現代碼的扁平化及公用化
  • Replace Parameter with Explicit Methods(以明確函數取代參數)
    • 當函數行為完全取決于參數value時,需要將這個函數拆分到多個方法,避免函數內部邏輯太雜
  • Reserve Whole Object(保持對象完整)
    • 當被調用函數的參數正好是某對象的其中幾個屬性時,則直接傳入這個對象
    • 需要同時考慮被調用函數是否需要move到這個對象中
  • Replace Parameter with Methods(以函數取代參數)
    • 如果主函數中包含有多個子函數,并且這些子函數返回值只是首尾傳入傳出
    • 此時,考慮將除最后一個函數外,其他子函數不通過主函數來調用,而是通過最后一個字函數的內部進行調用
  • Introduce Parameter Object(引入參數對象)
    • 當某些參數總是成對、成堆出現時,考慮此模式
    • 如: DateTime from, DateTime end==> DateRange
    • int pageIndex, int pageSize==>PagingInfo
    • 以及PagingResult<T>{TotalCount, List<T>}
  • Remove Setting Method(移除設值函數)
    • 如果某個類的屬性在構造后就不需要被改變,則把相應的set訪問器關閉
  • Hide Method(隱藏函數)
    • 如果某函數沒有被其他類引用到,就改成private的
  • Replace Constructor with Factory Method(以工廠函數取代構造函數)
    • 當類存在多個子類,并且希望通過類型碼來生成新對象時,可以將構造函數改成工廠方法,這樣便于客戶端調用,無需知道到底是哪個子類
  • Encapsulate Downcast(封裝向下轉型)
    • 是說對于類型的強制轉換,需要放在具體的函數中實現,不要放在客戶端代碼中
    • 現在.Net有了泛型,減少了很多這種麻煩
  • Replace Error Code with Exception(以異常取代錯誤碼)
    • 在代碼中如遇異常,則直接throw new XXXXException("xx"),而不是用return errorCode的方式
    • 如果是可控異常,則在catch(XXXException ex)處理掉
    • 如果是不可控異常,則無需處理
    • 不可控異常應有框架來處理,如AOP或者Global中的Error事件
  • Replace Exception with Test(以測試取代異常)
    • 對于濫用了catch異常的邏輯進行邏輯上的修改
    • 用單元測試+Assert+邊界值測試來確保某些異常沒有被觸發

處理概括關系

  • Pull Up Field(字段上移)
    • 當多個子類中存在相似的字段時,需要分析
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久噜噜噜久久久精品| 精品福利视频导航| 国产一区二区三区日韩欧美| 久久成人一区二区| 岛国av午夜精品| 91免费看视频.| 欧美日韩一区二区免费视频| 韩国美女主播一区| 亚洲福利视频专区| 国产一区二区三区视频在线观看| 91精品视频免费观看| 欧美理论片在线观看| 成人情趣片在线观看免费| 欧美国产日韩一区二区三区| 日韩在线观看免费全集电视剧网站| 亚洲欧美在线x视频| 国产精品久久久久久影视| 亚洲精品午夜精品| 亚洲xxxxx性| 91久久久久久国产精品| 亚洲成av人乱码色午夜| 欧美精品制服第一页| 91系列在线观看| 日韩av综合中文字幕| 中文字幕综合一区| 都市激情亚洲色图| 97视频在线看| 国产欧美精品va在线观看| 日韩精品在线影院| 亚洲成人999| 九九久久综合网站| 日韩欧美在线网址| 国产精品美女av| 亚洲一区二区三区成人在线视频精品| 日韩在线国产精品| 性欧美xxxx交| 98精品国产自产在线观看| 国产免费一区二区三区在线观看| 久久国内精品一国内精品| 亚洲欧美另类自拍| 欧美夫妻性视频| 最近2019年好看中文字幕视频| 欧美日本国产在线| 米奇精品一区二区三区在线观看| 亚洲国产精品一区二区三区| 国产一区二区色| 国产在线观看精品| 亚洲护士老师的毛茸茸最新章节| www.亚洲成人| 亚洲欧美激情在线视频| 韩国美女主播一区| 日韩电影第一页| 亚洲qvod图片区电影| 亚洲国产成人在线视频| 国内揄拍国内精品少妇国语| 欧美精品在线播放| 欧美日韩国产一区在线| 欧美巨猛xxxx猛交黑人97人| 亚洲国产精品久久久久| 亚洲区免费影片| 九九热最新视频//这里只有精品| 欧美高清视频一区二区| 欧美日韩在线视频一区二区| 精品国产欧美一区二区五十路| 久热精品视频在线免费观看| 中文字幕亚洲一区二区三区五十路| 91久久精品国产91性色| 奇米一区二区三区四区久久| 黑人精品xxx一区| 日韩成人av网址| 亚洲国产美女精品久久久久∴| 成人午夜小视频| 宅男66日本亚洲欧美视频| 91色精品视频在线| 久久国内精品一国内精品| 日韩精品中文字幕在线| 国产在线精品播放| 91亚洲午夜在线| 91tv亚洲精品香蕉国产一区7ujn| 91精品国产色综合久久不卡98| 国产精品视频xxxx| 2019最新中文字幕| 精品视频在线播放免| 91综合免费在线| 欧美一区二区三区免费视| 国产精品老牛影院在线观看| 国产在线不卡精品| 国产在线观看一区二区三区| 日韩精品在线观| 久久99热精品这里久久精品| 欧美怡春院一区二区三区| 成人av番号网| 91精品久久久久久久久久入口| 97人人模人人爽人人喊中文字| 欧美电影免费观看大全| 亚洲最大福利视频| 久久久久久久激情视频| 亚洲成人网av| 中文字幕亚洲无线码a| 欧美精品激情在线| 亚洲第一男人天堂| 国产精自产拍久久久久久蜜| 高清一区二区三区日本久| 岛国av一区二区三区| 日韩经典中文字幕| 午夜精品福利电影| 91精品在线一区| 夜夜躁日日躁狠狠久久88av| 欧美成人免费大片| 亚洲欧美激情四射在线日| 欧美福利视频网站| 国产999精品视频| 国产亚洲一区二区在线| 亚洲精品国产精品国产自| 欧美性极品少妇精品网站| 国产主播在线一区| 久久久久中文字幕| 亚洲男女性事视频| 成人激情综合网| 国产成人精品久久亚洲高清不卡| 久久综合色88| 久久综合亚洲社区| 国产日韩在线播放| 欧美亚洲视频一区二区| 日韩av在线网址| 日韩成人在线电影网| 欧洲成人在线视频| 国产亚洲激情视频在线| 九九热精品视频国产| 精品高清美女精品国产区| 蜜臀久久99精品久久久久久宅男| 精品久久久久久久久久久久久久| 91免费观看网站| 国产高清视频一区三区| 伊人久久男人天堂| 亚洲国产成人久久综合一区| 成人有码在线播放| 中文字幕九色91在线| 国产精品视频区1| 国产欧美精品一区二区| 色中色综合影院手机版在线观看| 69久久夜色精品国产69乱青草| 欧美黄色片视频| 亚洲美女中文字幕| 欧美性猛交99久久久久99按摩| 国产女精品视频网站免费| 国产日韩中文字幕在线| 精品国产一区二区三区久久狼黑人| 午夜精品一区二区三区在线视| 国产一区二区视频在线观看| 欧美视频在线观看 亚洲欧| 久久激情视频免费观看| 日韩视频免费大全中文字幕| 亚洲一区亚洲二区亚洲三区| 91国偷自产一区二区三区的观看方式| 亚洲精品在线不卡| 黄色一区二区在线观看| 日韩电影视频免费| 爽爽爽爽爽爽爽成人免费观看| 九九久久精品一区| 精品视频一区在线视频| 91色视频在线观看| 51视频国产精品一区二区| 中文字幕不卡av|