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

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

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

    Java, Only Java!

    統計

    留言簿(20)

    積分與排名

    好友空間

    文檔技巧

    閱讀排行榜

    評論排行榜

    《重構》的讀書筆記

  • 總覽
  • 第1章 重構,第一個案例
  • 第2章 重構原則
  • 第3章 代碼的壞味道
  • 第4章 構筑測試體系
  • 第12章 大型重構359
  • 第13章 重構,復用與現實379
  • 第14章 重構工具401

      《重構》的讀書筆記

      學習基礎:

      熟悉《設計模式》的基本概念,熟悉基本的Java語法,熟悉Eclipse和JUnit的使用,有相對較好的英語基礎。

      學習過程:

      • 先看第1章,手工輸入實例程序,了解重構的方法和過程。重點是理解重構的思路,最好的理解方式就是通過實踐的方式理解。
      • 再看第2~4章,內容為選擇性閱讀,沒興趣或者看不懂的都可以跳過,因為后面還可以回頭再讀。
      • 接著第5~12章,最好按順序把代碼一個個輸入,再按照作者的步驟重構操作一次,并結合自己以往工作中的實踐來理解。

      學習目的:

      使自己編寫的代碼更容易被人讀懂。

      學習感悟:

      • 代碼的重構應該是一步步完成的,每次重構的部分不要超過自己的理解能力的5%。雖然這樣操作略顯繁瑣,但是可以減輕頭腦重構過程中的記憶強度,減少代碼出錯的機會。
      • 代碼的重構一定要配合JUnit(TDD,測試驅動開發)完成,再加上Git(版本管理)和Eclipse(IDE的重構工具)那就事半功倍了。

      學習代碼:

      Refactored-MartinFowler

      總覽

      • 第1章(必讀),從實例程序出發,了解重構的方法和過程。
      • 第2章,討論重構的一般性原則、定義和進行重構的原因。
      • 第3章,介紹如何判斷問題代碼,以及如何用重構改善它們。
      • 第4章,在代碼中構建java的測試環境
      • 第5~12章,具體面對的問題和重構的方法。
      • 第13章,Bill Opdyke在商業開發中應用重構
      • 第14章,自動化重構工具(今天看來,已經不是太大問題,Eclipse的Refactor已經非常好用)
      • 第15章,重構的哲學思想

      第1章 重構,第一個案例

      1.1 (P1)起點

      因為代碼的結構無法滿足添加新功能的需要,因此先進行重構,使代碼方便添加新功能,然后再添加新功能。

      1.2 (P7)重構的第一步

      首先確認自己擁有一套可靠的測試機制,因為重構有可能引入問題,通過測試保證重構沒有改變程序功能。

      第2章 重構原則

      2.1 (P53)何謂重構

      重構(名詞):對軟件內部結構的一種調整,目的是在不改變軟件可觀察行為的前提下,提高理解性和降低修改成本。
      重構(動詞):使用一系列重構手法,在不改變軟件可觀察行為的前提下,調整其結構。
      定義的擴展:

      • 重構讓軟件更容易理解和修改
      • 重構不會改變軟件的可觀察行為,即使改變也只能是微小的影響,軟件功能一如既往。

      重構的目標:只改變程序內部結構,不添加新的功能

      不要一心二用:

      • 添加新功能的時候,不重構已有代碼。
      • 重構代碼時,不增加新功能。

      2.2 (P55)為何重構

      • 重構改進軟件設計:
        • 程序的設計質量在沒有持續重構的情況下逐漸變差,功能的增加或者修改都可能使代碼越來越難以理解和維護,就越難保證最初的設計目標
        • 消除重復的代碼一方面是程序運行更快,一方面是方便未來的修改,例如:重構減少代碼重復,避免功能的改變需要修改多處代碼。
      • 重構使軟件更容易理解:
        • 及時填補“想要它做什么”和“告訴它做什么”之間的縫隙。重構的核心就是要“準確說出我所要的”
        • 重新閱讀代碼的人有可能是自己,也可能是他人。
        • 通過重構可以把自己不熟悉的代碼的用途梳理一遍,加深對代碼的理解
      • 重構幫助找出bug:
        • 這個是建立在代碼容易理解之上的
      • 重構提高編程速度:
        • 重構達到良好的設計,而良好的設計更容易修改代碼、增加功能、問題調試。

      2.3 (P57)何時重構

      重構的三次法則:

      • 第一次開發某個功能的時候以實現為目標。
      • 第二次開發相同功能的時候,克制自己的反感,繼續重復實現。
      • 第三次開發相同功能的時候,應該重構。

      重構的時間點:

      • 添加功能時重構:
        • 一方面可以幫助理解需要修改的代碼
        • 一方面是使現在以及未來增加新功能更加容易。
      • 修補錯誤時重構:
        • 出現bug的時候,難以找出問題所在的時候,很有可能是代碼不清晰導致查找bug的困難。
      • 復審代碼時重構:
        • 復審代碼有助于知識的傳播,有利于代碼被編寫者之外的人理解。
        • 重構加深了對代碼的理解,有利于提升復審代碼的能力

      復審團隊:只要代碼作者和一個審查者者。較大的項目可以通過UML圖去展示代碼的邏輯。

      程序難以修改的原因:

      • 難以閱讀的程序
      • 邏輯重復的程序
      • 添加新特性需要修改已有代碼的程序
      • 帶復雜邏輯判斷的程序

      重構的目標:

      • 代碼容易閱讀
      • 所有邏輯都只有唯一地點指定
      • 新的改動不會危及現有行為
      • 盡可能簡單表達邏輯

      2.4 (P60)怎么對經理說

      • 懂技術的經理,很容易溝通;
      • 追求質量的經理,介紹重構對質量的幫助;
      • 追求進度的經理,則自己安靜地重構。因為重構可以最快的完成任務,就是對經理最大的幫助。

      間接訪問

      很多時候重構都為程序引入間接訪問:

      • 把大型對象拆分成小對象
      • 把大型函數拆分為小型函數。

      間接訪問的價值:

      • 允許邏輯共享:一個函數在不同地點被調用。子類共享超類的方法。
      • 分開解釋意圖和實現:通過類名和函數名解釋自己的意圖
      • 隔離變化:在不同地方使用同一個對象,需要修改一處邏輯,那么可以做出子類,并在需要的時候修改這個子類。
      • 封裝條件邏輯:運用多態。將條件邏輯轉化為消息模式。

      減少間接層的條件:當間接層只在一處使用,那么需要將其消除。

      2.5 (P62)重構的難題

      數據庫重構:

      • 存在問題:
        • 程序與數據庫耦合在一起。
        • 數據遷移。
      • 解決方案:
        • 在非關系型數據庫,可以在數據庫和對象模型中插入一個分離層,隔離兩者之間的變化

      接口重構

      • 對于已經發布的接口需要可能需要維護舊接口和新接口,用deprecated修飾舊接口。
      • 不發布新接口,在舊接口中調用新接口。
      • 假如新接口拋出編譯時異常,那么可以在舊接口中調用新接口并將編譯時異常轉化為運行時異常。

      不重構的條件:

      • 重構之前,代碼在大部分情況下都能夠正常運行,就可以重構,否則應該是重寫。
      • 到了Deadline,應該避免重構。

      2.6 (P66)重構與設計

      重構與設計是彼此互補的:

      • 設計應該在編碼之前,但是設計總有缺陷,隨著對問題認識的逐漸深入,通過重構可以改善設計的質量。
      • 重構減輕了設計的難度和壓力,在程序不斷修改的過程中逐步完善程序的設計。

      2.7 (P69)重構與性能

      重構是有可能導致程序運行變慢的,但是不需要在設計和編碼時就考慮性能問題。例如:實時程序的編寫:

      • 首先寫出可調的程序
      • 然后調整它以達到性能的要求。
        • 經過分析大部分程序的主要時間是消耗在小部分代碼上,所以不用對所有代碼進行優化。
        • 性能優化放在開發的后期,利用分析工具找出消耗大量時間的代碼,然后集中優化。

      第3章 代碼的壞味道

      3.1 (P76)Duplicated Code(重復代碼)

      • 同個類兩個函數存在相同表達式:Extract Method(提煉函數)
      • 互為兄弟類內存在相同表達式:
        • Extract Method→PullUp Method(函數上移)
        • 如果代碼只是相似:先運用Extract Method(提煉函數)分開再Form TemPlate Method(塑造模板函數)
      • 兩個毫不相干的類存在重復代碼:Extract Class(提煉類)

      3.2 (P76)Long Method(過長函數)

      原則:盡量利用函數名稱來解釋用途,而不是注釋。
      關鍵:代碼主要用來描述“做什么”,而不是描述“怎么做”。例如:getAge()表達獲取年齡,而today-birthday就增加了理解的間接性,雖然看代碼的人也能明白含義,但是就需要多想一下,并且birthday有可能表達的不是某個人的出生日期呢,而是某個買回來的產品的呢?那可能表達的就是使用時長了。
      具體情況:

      • 函數有大量參數和臨時變量:Extract Method(提煉函數)
      • 用Replace Temp with Query(以查詢取代臨時變量)消除臨時變量
      • 用Introduce Parameter Object(引入參數對象)或者Preserve Whole Object(保持對象完整)來將多長的參數列表變得簡潔一點。
      • 如果按照上述步驟還存在太多變量和參數就需要用到Replace Method with Method Object(以函數對象取代函數)
      • 條件表達式可以用Decompose Conditional(分解條件表達式)解決
      • 可以將循環內的代碼提煉為函數。

      3.3 (P78)Large Class(過大的類)

      有時候類并非在所有時刻都使用實例變量:使用Extract Method和Extract Subclass(提煉子類)

      類中有太多代碼:

      • Extract Class(提煉類)
      • Extract Subclass(提煉子類)
      • Extract Interface(提供接口)分解類的行為。存在GUI的時候,可以Duplicate Observed Data(復制“被監視數據”),分離數據和行為到業務模型中去。

      3.4 (P78)Long Parameter List(過長參數列)

      • 如果可以調用已有對象獲取的話可以使用Replace Parameter with Methods(以函數取代參數)
      • 將來自同一對象的數據收集起來,以該對象替代:Preserve Whole Object(保持對象完整)
      • 如果幾個參數總是同時出現,那么可以考慮Introduce Parameter Object(引入參數對象)

      3.5 (P79)Divergent Change(發散式變化)

      不同的變化影響著相同的類發生改變,即變化的認知有分歧(Divergent)。通過Extract Class把不同的功能封裝到不同的類中,使每個類只因一種變化而需要修改

      3.6 (P80)Shotgun Surgery(霰彈式修改)

      相同的變化會涉及到多個類發生修改,類似霰彈槍射擊的效果。
      可以通過Extract Method,Move Method,Inline Class把一種變化產生的多個修改移到同一個類中。

      對比:

      • Divergent Change(發散式變化)是一個類受到的多個變化影響;
      • Shotgun Surgery(霰彈式修改)是一個變化引起多個類需要修改。

      3.7 (P80)Feature Envy(依戀情結)

      類中的某個函數對其他類的依賴度過高,則應該通過Move Method(移動函數)將它搬移到合適的類中。

      3.8 (P81)Data Clumps(數據泥團)

      數據項總是成群結隊出現,通過Extract Class將它們提煉到一個獨立對象中,從而縮短參數列表,簡化函數調用。

      判斷數據項是否相關的方法:如果這些數據項不在一起時就失去了明確的含義,那么就可以把它們提煉成一個新的對象。

      3.9 (P81)Primitive Obsession(基本類型偏執)

      • 有些字段可以用對象表示更準確Replace Data Value with Object(以對象取代數據值)
      • 對于不影響行為的類型碼可以Replace Type Code with Class(以類取代類型碼)
      • 影響行為的類型碼可以Replace Type Code with Subclasses(以子類取代類型碼),類型碼在運行時會變化就用Replace Type Code with State/Strategy(以State/Strategy取代類型碼)

      3.10 (P82)Switch Statements(switch驚悚現身)

      • 使用Replace Type Code with Subclasses(以子類取代類型碼)或者Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
      • 輕量級的解決方法:Replace Parameter with Explicit Methods(以明確函數取代參數)

      3.11 (P83)Parallel Inheritance Hierarchies(平行繼承體系)

      每當為一個類增加子類必須也為另外一個類增加一個子類,那么就讓一個繼承體系的實例引用另一個繼承體系的實例。

      3.12 (P83)Lazy Class(冗贅類)

      沒用的類,使用Inline Class(內聯類)或者Collapse Hierarchy(折疊繼承體系)來解決

      3.13 (P83)Speculative Generality(夸夸其談未來性)

      • 為未來設計的類,使用Inline Class(內聯類)或者Collapse Hierarchy(折疊繼承體系)來解決
      • 為未來設計的函數參數,使用Remove Parameter(移除參數)
      • 函數名稱啰嗦,使用Rename Method(函數改名)

      3.14 (P84)Temporary Field(令人迷惑的暫時字段)

      對象中某個字段僅為特定情況而設。使用Extract Class(提煉類)將這個字段提取出來

      3.15 (P84)Message Chains(過度耦合的消息鏈)

      消息鏈:用戶通過一個對象獲取另一個對象,再通過獲取的對象請求另一個對象,如此操作就是消息鏈。采取這種方式意味著客戶代碼將與查找過程中的導航結構緊密耦合,可以使用Hide Delegate(隱藏“委托關系”)進行重構。但是謹慎處理!

      3.16 (P85)Middle Man(中間人)

      過度委托形成中間人:Remove Middle Man(移除中間人)

      如果中間人還有其他行為,Replace Delegation with Inherited(以繼承取代委托)

      3.17 (P85)Inappropriate Intimacy(狎昵關系)

      • 兩個類相互依賴過多,花費大量時間去獲取對方的private成員內容,使用Move Field(移動字段)和Move Method(移動方法)減少耦合性,或用Change Bidirectional Association to Unidirectional(將雙向關聯改為單向關聯)
      • 如果兩個類無法移動相同數據和函數,可以使用Extract Class(提煉類),讓他們使用新類進行交互。

      3.18 (P85)Alternative Classes with Different Interfaces(異曲同工的類)

      兩個函數做了相同的事情卻有不同的函數名稱

      3.19 (P86)Incomplete Library Class(不完美的庫類)

      庫函數功能不足,需要增加一些自定義的功能:

      • 需要加入少量操作,使用Introduce Foreign Method(引入外加函數)
      • 需要加入大量操作,使用Introduce Local Extension(引入本地擴展)

      3.20 (P86)Data Class(幼稚的數據類)

      幼稚的數據類:只有數據沒有行為的類,其他類需要對該類的數據進行取值設值操作

      • 使用Encapsulate Field(封裝字段)和Encapsulate Collection(封裝集合)對字段進行合理地封裝
      • 對于不該被其他類修改的字段:Remove Setting Method(移除設值函數)

      3.21 (P87)Refused Bequest(被拒絕的遺贈)

      如果子類不愿意接受超類的所有定義,應該使用Replace inherited with Delegation(以委托取代繼承)來處理子類

      3.22 Comments(過多的注釋)87

      使用Extract Method(提煉方法)來解決注釋過多問題,注釋更多應該說明的是“怎么做”,而不是“做什么”,例如:對一個排序函數說明其采用二分法排序,而不是說明它是個排序函數,因為這個說明在函數名稱中已經具備。

      第4章 構筑測試體系

      4.1 自測試代碼的價值89

      • 確保所有測試都完全自動化,讓它們檢查自己的測試結果;
      • 一套測試就是一個強大的bug探測器,能夠大大縮減查找bug所需要花費的時間。
        • 因為代碼剛剛寫完,測試出現問題后,心里很清楚自己修改或者添加了哪些東西,可能會在哪里出現了問題。

          4.2 JUnit測試框架91

      • 頻繁地運行測試;
      • 每次編譯前都進行一次測試;
      • 每天至少執行一次所有的測試。

        4.3 添加更多測試97

      • 編寫一個測試并運行起來,好過將所有的測試編好了一起運行。
      • 測試特別需要注意可能出錯的邊界條件;
      • 對于可能出錯的地方,還需要檢查是否拋出了預期的異常;
      • 測試不能解決所有bug,但是可以大大減少bug的數量。

      第12章 大型重構359

      大型重構是程序開發必將遇到的,只是不知道在什么時間,用什么樣的方式經歷。例如:隨著時間的推移,河道必定會被水草和垃圾所堵塞,你可以固定時間清淤,也可以放任自流直到崩潰。崩潰后依然會面臨總結經驗教訓,再次重構系統。
      大型重構很難給出具體的操作案例,因為每個大型案例相對于自身來說都是惟一的,是無法復制和重現的。可以復制與重現的都是這些大型重構中蘊含的具體的細節,因此這章主要講的是思想和理念上的內容。
      四個大型重構:

      • Tease Apart Inheritance(362)用于處理混亂的繼承體系
        • 某個繼承體系同時承擔兩項責任
        • 建立兩個繼承體系,其中一個通過委托調用另一個
      • Convert Procedural Design to Objects(368)如何重構過時的編碼技術遺留下來的程序
        • 傳統過程化風格的代碼
        • 將數據記錄變成對象,將大塊的行為分成小塊,再將它們移入到相關對象中
      • Separate Domain from Presentation(370)將業務邏輯與用戶界面分隔開來
        • 用戶界面類中包含了業務邏輯
        • 將業務邏輯剝離到業務類中,參考:MVC模式
      • Extract Hierarchy(375)將復雜的類轉化為一群簡單的子類,從而簡化系統。
        • 某個類做了太多工作
        • 某個類的部分工作是由大量的條件表達式完成的
        • 建立繼承體系,使用子類表示每一種特殊情況

      第13章 重構,復用與現實379

      作為一個博士寫的內容,仍然具有學術性較強的風格,可以當作歷史資料了解一下重構的發展過程,也可以對重構的思想有更多理論上的認識。

      安全重構(391)

      安全重構的四條籬笆:

      • 相信你自己的編碼能力;
      • 相信你的編譯器能捕捉你遺漏的錯誤;
      • 相信你的測試套件能捕捉你和編譯器都遺漏的錯誤;
      • 相信代碼復審能捕捉你、編譯器和測試套件都遺漏的錯誤。注:沒有100%安全的重構,但是可以通過以上的條件滿足你對安全性的最低要求。

      重構工具

      • Eclipse(或其他IDE)自帶的重構工具:Refactor;
      • Java(或其他編譯器)自帶的分析工具:lint;
      • JUnit等自動化的測試工具。

      第14章 重構工具401

      相對于10多年前寫的內容,現在許多IDE都已經提供了對大部分重構功能的支持。但是了解重構的基本理念,對于正確地使用重構工具會有很大的幫助。因為成功的重構不依賴于工具,而決定于人,當人做出了正確的決定,合理地使用重構工具輔助自己,才能保證重構的完成。

    • posted on 2019-01-16 17:48 zYx.Tom 閱讀(208) 評論(0)  編輯  收藏 所屬分類: 6.我的感想

      主站蜘蛛池模板: 99re视频精品全部免费| 一级免费黄色大片| 日韩版码免费福利视频| 亚洲午夜精品久久久久久人妖| a级在线观看免费| 好看的亚洲黄色经典| 美女在线视频观看影院免费天天看 | 精品亚洲一区二区| 国产免费伦精品一区二区三区 | 永久中文字幕免费视频网站| 一本天堂ⅴ无码亚洲道久久| 高清国语自产拍免费视频国产| 九九精品国产亚洲AV日韩| 亚洲AⅤ永久无码精品AA| 一级一级一级毛片免费毛片| 亚洲乳大丰满中文字幕| 99re热精品视频国产免费| 亚洲综合在线一区二区三区| 国产中文字幕免费| 国产乱子伦精品免费视频| 亚洲爆乳精品无码一区二区三区| 95免费观看体验区视频| 激情综合亚洲色婷婷五月| 免费看一级做a爰片久久| 精品一区二区三区免费观看 | 午夜国产大片免费观看| 亚洲毛片网址在线观看中文字幕| 在线观看免费黄网站| 亚洲成a人片毛片在线| 日美韩电影免费看| 一个人看的www免费视频在线观看| 亚洲码一区二区三区| 免费国产在线观看老王影院| 99视频免费在线观看| 亚洲日韩久久综合中文字幕| 亚洲人妻av伦理| 国产免费不卡v片在线观看| 一级毛片在线完整免费观看| 久久狠狠高潮亚洲精品| 国产成人免费全部网站| 99re6在线精品视频免费播放|