《重構與模式》讀書筆記
學習基礎:熟悉《設計模式》和《重構》的概念,熟悉基本的Java語法和XML語法,熟悉Eclipse和JUnit的使用,有相對較好的英語基礎。
學習過程:
先按P40的學習順序讀完序號1~9。理解每個重構模式的動機,嘗試讀懂示例中的代碼(實在不懂就放過,找機會上機也能明白)。
在時間允許的條件下,可以重讀和對書中代碼重構,從而更加充分地理解重構與模式這兩個重要的概念和實踐方法。
學習目的:使自己編寫的代碼更容易被人讀懂。
學習感悟:
代碼的重構應該是一步步完成的,每次重構的部分不要超過自己的理解能力的5%。雖然這樣操作略顯繁瑣,但是可以減輕頭腦重構過程中的記憶強度,減少代碼出錯的機會。
代碼的重構一定要配合JUnit(TDD,測試驅動開發)完成,再加上Git(版本管理)和Eclipse(IDE的重構工具)那就事半功倍了。
一、構造函數
(一)、構造函數的重構:
6.1. (P43)用Creation Method替換構造函數:用明確的創建方法代替類中的多個構造函數,避免創建新類時客戶無法正確理解和使用構造函數的意圖。
優點與缺點:
+ 相比構造函數能夠更好地表達所創建的實例的意圖;
+ 避免了構造函數的局限性,例如:兩個構造函數不能通過相同的參數和不同的返回類型進行重載;
+ 更容易發現無用的創建代碼;
- 非標準化的創建方式,例如:不是統一用new的方式實例化。
11.1.(P275) 構造函數鏈:把構造函數鏈接起來,減少代碼的重復。特殊的構造函數調用更通用的構造函數,直到全包含構造函數(處理所有的構造函數調用)。
當構造函數數量過多時,可以使用Creation Method(6.1節)重構。
(二)、Factory的使用
6.3. (P60)用Factory封裝類:將同一個包里面、實現了相同接口的多個類的實例化交由工廠完成。
優點與缺點:
+ 通過Creation Method簡化不同種類實例的創建;
+ 通過隱藏類減少包結構的“概念重量”;
+ 通過共享公共接口實踐“面向接口編程,而不要面向實現編程”的理念;
- 增加新的種類的實例時,必須修改或者增加新的Creation Method;
- 當客戶只能獲得Factory的二進制代碼而不是源代碼時,對Factory的制定將受到限制。
6.4. (P67)用Factory Method引入多態創建:將同樣的超類,不同的創建過程統一交由工廠完成。
優點與缺點:
+ 減少因創建自定義對象而產生的重復代碼;
+ 有效地表達了對象創建發生的位置,以及如何重寫對象的創建;
+ 強制Factory Method使用的類必須實現統一的接口;
- 可能會向Factory Method的一些實現者傳遞不必要的參數。
算法重構
Strategy
7.2.(P102) 用Strategy替換條件邏輯
優點與缺點:
+ 通過減少或者去除條件邏輯使算法變得清晰易懂;
+ 通過把算法的變體搬移到類層次中簡化了類;
+ 允許在運行時用一種算法替換另一種算法;
- 增加設計的復雜度;
- 增加了算法獲取數據的復雜度。
Template Method
8.1. (P166)形成Template Method:通過將不同方法中相同的順序執行步驟提取出來從而實現泛化。
優點與缺點:
+ 通過把不變行為搬移到超類,去除子類中的重復代碼;
+ 簡化并有效地表達了一個通用算法的步驟;
+ 允許子類很容易地定制一個算法;
- 當為了生成算法導致子類必須實現很多方法的時候,就增加了設計的復雜度。
Composite
XMLBuilder的例子依據的有(7.5)TagNode,(6.5)TagBuilder,(10.1)TagNode,代碼中存在一些小問題,可以試著自己修改。
7.1. (P97)Composed Method(組合方法)模式:將代碼組合成名字簡單易懂的方法,再將這些方法組合成更大的方法,從而方便讀懂代碼。
優點與缺點:
+ 清晰地描述了一個方法所實現的功能以及如何實現;
+ 把方法分解成命名良好的、處在細節的同一層面上的行為模塊,以此來簡化方法;
- 可能會產生過多的小方法;
- 可能會使調試變得困難,因為程序的邏輯分散在許多小方法中。
7.5. (P143)Composite模式:隱式地構造出樹形結構。
優點與缺點:
+ 封裝重復的指令,如格式化、添加或刪除結點;
+ 提供了處理相似邏輯增長的一般性方法;
+ 簡化了客戶代碼的構造職責;
- 構造的隱式的樹結構越簡單,設計的時候就越復雜。
6.5. (P74)用Builder封裝Composite:因為構造Composite有許多重復工作,并且工作流程是復雜而且容易出錯的,通過Builder來處理構造細節來簡化構造過程。
優點與缺點:
+ 簡化了構造Composite的客戶代碼;
+ 減少了創建Composite的重復和易出錯的問題;
+ 在客戶代碼和Composite之間實現了松耦合;
+ 允許對已經封裝的Composite或復雜的對象創建不同的表示;
- 接口可能無法清楚地表達其本質意圖。
10.1. Collecing Parameter(聚集參數)模式:是把一個對象傳入到不同的方法中,從而在這些方法中收集信息。
經常與Composed Method模式一起使用。
優點與缺點:
+ 可以把很大的方法轉換成更上的、更簡單的方法;
- 少量地影響結果代碼的運行速度。
8.2.(P172) 提取Composite:將同一個超類下的多個子類實現的同樣的Composite提取到超類中。
優點與缺點:
+ 去除重復的類存儲邏輯和類處理邏輯;
+ 能夠有效地表達類處理邏輯的可繼承性。
8.3.(P180) 用Composite替換一個對象和多個對象的分別:用Composite實現了既可以處理一個對象,也可以處理多個對象的同樣的函數接口。
優點與缺點:
+ 去除了處理一個對象的方法和多個對象的方法中重復的代碼;
+ 提供了處理一個對象和多個對象的統一函數方法;
+ 提供了處理多個對象的更豐富的方法(例如:OR表達式);
- 可能會在Composite的構造過程中要求類型安全的運行時檢查。
Command
7.6.(P155)用Command替換條件調度程序:為動作創建Command,將這些Command存儲在集合中,再通過集合取出對應的Command執行。
缺點與優點:
+ 提供了用統一方法執行不同行為的簡單機制;
+ 允許在運行時改變所處理的請求,以及如何處理請求;
+ 僅僅需要很少的代碼實現;
- 會增加設計的復雜度,有時還不如條件調度程序簡單。
Adapter
8.6.(P208)提取Adapter:一個類適配了多個版本的組件、類庫、API或其他實體,可以通過提取Adapter來統一接口。
缺點與優點:
+ 隔離不同版本的組件、類庫或API之間的區別;
+ 使類只負責適配代碼的一個版本;
+ 避免了頻繁地修改代碼;
- 因為Adapter帶來的限制,阻止了客戶調用Adapter沒有提供的功能。
8.5.(P99)通過Adapter統一接口:使用客戶代碼與多個類交互時,遵循統一接口完成。
優點與缺點:
+ 客戶通過相同的接口與不同的類交互;
+ 客戶通過公共的接口與多個對象交互;
+ 客戶與不同的類交互方式相同;
- 當類的接口可以改變的時候,增加了設計的復雜度。
Adapter模式與Facade模式的區別
Adapter用來適配對象;
Facade用來適配整個子系統;通常用來與遺留系統進行交互。
它們都可以使代碼易于使用,但是它們的應用級別不同。
State
9.1.(P231)用類替換類型代碼:保護字段從而避免不正確或者不安全的賦值。
采用類替換類型代碼而不用枚舉,是因為類可以考慮未來行為的擴展,但是現在Java的枚舉功能更加強大了,所以可以根據自己的習慣來選擇。
當重構過程中產生的類需要擴展包含更多行為時,就可以考慮(7.4.State替換狀態改變條件語句)進行重構了。
缺點與優點:
+ 避免非法賦值和比較;
- 比使用不安全類型需要更多的代碼。
7.4. 用State替換狀態改變條件語句:簡化復雜的狀態轉換邏輯
優點與缺點:
+ 減少復雜的狀態轉換條件邏輯;
+ 簡化復雜的狀態改變邏輯;
+ 提供觀察狀態改變邏輯的角度;
- 增加設計的復雜度。
9.3. 引入Null Object:替換掉null的判斷邏輯,提供了對null的正確處理。
優點與缺點:
+ 不需要重復的null邏輯就可以避免null錯誤;
+ 通過最小化null測試簡化了代碼;
- 當系統不太需要null測試的時候,會增加設計的復雜度;
- 如果程序員不知道Null Object的存在,就會產生多余的null測試;
- 使維護變得復雜,擁有超類的Null Object必須重寫所有新繼承到的公共方法。
Singleton
6.6. 將Singleton內聯化:把Singleton的功能搬移到需要它的類中,然后刪除Singleton。
優點與缺點:
+ 使對象的協作變得更加明顯和明確;
+ 保護了單一的實例,而且不需要特別的代碼;
- 當在許多層次間傳遞對象實例比較困難的時候,增加了設計的復雜度。
9.2. 用Singleton限制實例化:減少內存的占用,提高運行的速度。
優點與缺點:
+ 改進性能;
- 變成全局訪問;
- 當對象含有不能共享的狀態時,重構無法進行。
Observer
8.4.(P190)用Observer替換硬編碼的通知:
優點與缺點:
+ 使主題及其觀察者訪問松散耦合;
+ 支持一個或多個觀察者;
- 增加設計的復雜度;
- 面對串聯通知的時候,會進一步增加設計的復雜度;
- 當觀察者沒有從主題中刪除的時候,會造成內存泄漏。
注:例子不熟悉,所以代碼沒太能領悟
Decorator
7.3. (P115)將裝飾功能搬移到Decorator:
優點與缺點:
+ 將裝飾功能從類中搬移去除可以簡化類;
+ 有效地將類的核心職責與裝飾功能區分開;
+ 可以去除幾個相關類中重復的裝飾邏輯;
- 改變了被裝飾對象的對象類型;
- 會使代碼變得難以理解與調試;
- 當Decorator組合產生負責影響的時候會增加設計的復雜度。
注:這部分的代碼也不完備,理解起來有困難,建議大致了解作者思路就好了,Decorator應該是個應用比較廣泛的模式,以后自己可以通過實踐探索。
Decorator與Strategy的區別:
+ 都可以去除與特殊情況或選擇性行為相關聯的條件邏輯;
+ 都通過把條件邏輯搬移不對勁新的類中達到這一目的;
- Decorator主要把自己包裝在一個對象之外
- Strategy則用在一個對象之中。
11.2.(P278)統一接口:找出所有子類的公共方法,復制到超類中,在超類中執行空行為。
11.3.(P280)提取參數:通過客戶代碼提供的參數對字段進行賦值。
注:這兩節都是輔助Decorator進行重構的。
6.2.(P51)將創建知識搬移到Factory:避免創建代碼到處蔓延。
優點與缺點:
+ 合并創建邏輯和實例化配置選項;
+ 將客戶代碼與創建邏輯解耦;
- 如果可以直接實例化,用Factory就會增加設計復雜度。
注:可能作者認為采用的是HTMLParser的原因,所以給出的代碼不全,不利于理解重構的含義。
Visitor
10.2.(P259)將聚集操作搬移到Visitor:適用于從多個對象中聚集信息,適用于從不同的對象中聚集信息。使用起來難度較大,首選應該是Collecting Parameter方法(P253,10.1.)。
優點與缺點:
+ 調節多個算法,使其余適用于不同的對象結構;
+ 訪問相同或不同繼承結構中的類;
+ 調用不同類上的類型特定方法,無需類型轉換;
- 新的可訪問類需要新的接收方法,每個Visitor中需要新的訪問方法;
- 可能會破壞被訪問類的封裝性;
- 增加了代碼的復雜度。
注:
- 盡量使用通用接口把互不相同的類轉變成相似的類,而少用Visitor模式。
- Ralph Johnson:大多時候并不需要Visitor,有些時候則是必須要用,別無選擇。
- 可能作者認為采用的是HTMLParser的原因,所以給出的代碼不全,不利于理解重構的含義。
8.7.(P217)用Interpreter替換隱式語言
優點與缺點:
+ 比隱式語言更好的支持語言元素的組合;
+ 不需要新的代碼來支持語言元素的新組合;
+ 允許行為的運行時配置;
- 會產生定義語法和修改客戶代碼的開銷;
- 如果語言很復雜,編程工作量較大;
- 如果語言很簡單,不需要考慮使用這個模式,否則會增加設計的復雜度。
2019.1.2.晨,結束閱讀。學習代碼下載
注:這種讀書筆記對他人幫助不大,因為這個只是為了進一步理解作者的意圖而進行的工作,通過輸入關鍵點來確認自己是否真正領悟了作者想表達的意思。
當輸入這些優點與缺點時并沒有領悟,然后再通過輸入代碼來理解作者如何從一段不好的代碼重構成一段好代碼的,重構的過程中得到了什么、失去了什么,自己未來編寫程序中應該如何平衡。
補充1:不要在意輸入代碼中出現的錯誤,那是因為代碼不完備,許多類或者函數沒有提供源代碼。只要輸入的代碼可以排版和使用自動提示工具,就說明代碼符合Java的語法規范,那么在閱讀全書的過程中可以一點點把代碼補全,或者根據自己的理解補全(這也是個理解重構和提高編碼能力的機會)。
補充2:如果需要下載HTMLParser,請注意是1.3的版本才是作者使用的。但是與HTMLParser相關的例子與原代碼并不完全相同,而作者并沒有在自己的例子中把邏輯構造完整,因此建議跟HTMLParser相關的例子還是跳過吧,否則為了調試通過消耗時間太多。(我現在開始渴望直接看《重構》那本書了。)
代碼目錄:
貸款風險估算程序(6.1,7.2,8.1,11.1)
HTMLParser(6.2,7.3,8.2,10.1,10.2,11.2,11.3)
對象-關系數據映射(6.3)
XMLBuilder(6.4,6.5,7.5,8.5)
二十一點游戲(6.6)
集合類庫(7.1)
SystemPermission(7.4,9.1,9.2)
Product(8.3,8.7)
CatalogApp(7.6)
JUnit(8.4)
數據庫查詢(8.6)
Applet(9.2)
posted on 2019-01-02 11:25 zYx.Tom 閱讀(926) 評論(0) 編輯 收藏 所屬分類: 1.Java世界