《重構》讀書筆記 與 Eclipse 重構功能使用

來源:互聯網
上載者:User

標籤:des   blog   http   io   ar   os   使用   sp   for   

第二章 重構原則
重構是什嗎?
重構(名詞):對軟體內部結構的一種調整,目的是在不改變[軟體之可察行為]前提下,提高其可理解性,降低其修改成本。
重構(動詞):使用一系列重構準則(手法),在不改變[軟體之可察行為]前提下,調整其結構。

兩頂帽子:添加新功能和重構,不能同時進行。

為何重構?
改進軟體設計:可能設計之初根據已有需求,是世界上最優的設計。但是可能過程中增刪許多功能,原有設計已經不滿足現有需求。
使軟體更易理解:
     通常多添加註釋不一定是好的選擇,因為可能代碼會被別人修改,而忽略修改注釋。後續的人在看注釋反倒成了阻礙理解。
     程式是寫給人看的,不是寫給電腦看的。
找到BUG:重構的過程需要梳理流程,可以找出多個功能,或者多次迭代耦合放到一起的BUG
提高編程速度:便於理解,本身就是提高,新增功能的開發速度。


何時重構?
添加功能時、修改錯誤時、審查代碼時、

重構的難題?
資料庫、修改介面、

何時不改重構?
代碼邏輯混亂,完全不能新增東西,可能某些情況下需要完全重寫,不過還是建議先拆分成多個小模組,然後逐步重構與重建。
項目已經接近期限。

先設計後開發,但是沒必要非得為求最靈活的設計方案而擔憂。只需要選擇一個最合理的方案,實施然後實踐中不斷嘗試、驗證、反饋、再修改。
因為永遠不可能在前期預知到後續的變化,而且不可能設計時能考慮到所有細節,也沒有必要。

重構與效能?
三種方式
     時間預演算法(評估每次任務執行時間與執行鏈條)
     持續關注法(過程中注意,不過有些時候會導致開發速度變慢,或者程式難以理解)
     開發後期(關注比較大的效能消耗)


重構的起源?
1980年Smalltalk



第三章 代碼的壞味道
3.1 Duplicated Code(重複代碼)
     重複邏輯的函數(同一個類、多個子類中、不同類中)
3.2 Long Method(過長函數)
     一個函數僅有一個功能,在此情況下,很少超過15行
     方法內的功能越多,越難以複用。或者冗餘的複用

3.3 Large Class(過大的類)
3.4 Long Parameter List(過長參數列)
     或者過多的全域變數,可以把變化劃分為到新類中

3.5 Divergent Change(發散式變化)
     原本一個類中要承載太多功能。

3.6 Shotgun Surgery(霰彈式修改)
     一個功能的開發,需要牽扯到很多地方的修改。為什麼不把一類功能放入一個類中呢?

3.7 Feature Envy(依戀情結)
     將總是一起變化的東西放到一起。資料和引用這些資料的行為總是一起變化的。

3.8 Data Clumps(資料泥團)
     一個類中的資料太多,或者太少而分布在多個類中

3.9 Primitive Obsession(基本類型偏執)
     不願意把一類型的資料來源放到一個建立資料類中

3.10 Switch Statements(switch驚悚現身)
     是否使用多態替換

3.11 Paralle lInheritance Hierarchies(平行繼承體系)
     子類都有的函數,抽取到父類中。 或者乾脆建立類以建立對象引用的方式使用。

3.12 Lazy Class(冗贅類)
     本身很複雜,重構後功能是在太少,或者很少地方調用,乾脆把這個類刪除。

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

     過度設計,說是為了以後便於擴充,但是可能很久是只是單一的使用。


3.16 Middle Man(中間人)
     某個類一半的函數都是委託給其他class。

3.14 Temporary Field(令人迷惑的暫時欄位)
     零散的資料,抽到一個建立資料類中


3.15 Message Chains(過度耦合的訊息鏈)
     A對象一個功能需要調用B -> C -> D -> F -> E。最後E中才有想要的功能,是否可以把過程都直接抽取到一起,A直接調用抽取後的對象。(公用對象)

3.17 Inappropriate Intimacy(狎昵關係)
     父類與子類之間過度調用,或者兩個類見,過多的互相調用,乾脆把過度調用的方法放到一起。

3.18 Alternative Classeswith Different Interfaces(異曲同工的類)
     類或者函數差不多


3.19 Incomplete Library Class(不完美的庫類)
     為類庫添加擴充

3.20 Data Class(純稚的資料類)
3.21 Refused Bequest(被拒絕的遺贈)
     某些類的子類,並不需要其父類的功能


3.22 Comments(過多的注釋)




第六章 重新組織函數
6.1 Extract Method(提煉函數)
動機:
     函數粒度更小,複用的機會更大。
     高層函數讀起來像一系列注釋
     函數的複寫也會容易些
做法:
Eclipse 選中幾行代碼,選擇Refactory -> Extract Method 或者使用快速鍵(Alt + Shift + M)
任意選中一塊代碼,自動轉換為函數,自動添加參數傳回型別。

6.2 Inline Method(內嵌函式)
動機:有時可能發現直接使用函數中的代碼比抽取為函數更便於理解。
做法:
Eclipse 選中函數名,選擇Refactory -> Inline或者使用快速鍵Alt + Shift + I
把調用此函數的地方直接替換成此函數的內容。選中任意函數才可使用此功能。(有All invocations 與 Only the selected invocation兩個選項)

6.3 InlineTemp(內聯臨時變數)
動機:某些臨時變數可能印象重構
直接修改為對變數的使用,而刪除臨時變數

6.4 ReplaceTempwithQuery(以查詢取代臨時變數)
動機:阻礙抽取函數,把計算放入固定函數中

6.5 IntroduceExplainingVariable(引入解釋性變數)
Eclipse 選中運算式,選擇Refactory -> Extract Local Variable或者使用快速鍵Alt + Shift + L
通常用於運算式,把其中一個抽取為本地的變數,例如3 + 5 抽取為 int i = 3;

6.6 SplitTemporaryVariable(分解臨時變數)
動機:一個臨時變數僅被賦值一次,如果賦值多次說明承擔了一個以上的職責。這樣容易讓閱讀者糊塗。

6.7 RemoveAssignmentstoParameters(移除對參數的賦值)
值傳遞(pass-by-value)
     http://www.blogjava.net/heis/archive/2009/04/23/267256.html
引用傳遞(pass-by-refrence)


6.8 ReplaceMethodwithMethodObject(以函數對象取代函數)
     如果發現一個函數中有大量的臨時變數導致無法拆分成細粒度的函數,可以把此函數放入新類中,這樣函數中的臨時變數就成了此類中的全域變數,可以隨意抽取細粒度函數。


6.9 SubstituteAlgorithm(替換演算法)






第七章 在對象之間搬移特性


在對象設計過程中,決定把職責放在哪兒是非常重要的一件事情。通常很苦惱,但是運用重構可以改變自己原本的設計。

7.1 Move Method(搬移函數)
動機:兩個類之間有太多耦合行為,這樣可以通過搬移函數,使得兩個類變得乾淨利落。
做法:
     把要搬移的函數設定為static,這樣可以看到所有此方法中對當前類全域變數、方法的引用,把這些替換成函數的參數傳入。
     然後使用Eclipse 選中函數名,選擇Refactory -> Move 或者使用快速鍵(Alt + Shift + V)把欄位移到其他類、把類移到其他包

7.2 Move Field(搬移欄位)
動機:隨著系統的發展,發現自己需要新的classes,並需要將原本的工作責任拖到新class中。
做法:使用Eclipse 選中欄位,選擇Refactory -> Move 或者使用快速鍵(Alt + Shift + V)把欄位移到其他類、把類移到其他包

7.3 Extract Class(提煉類)
動機:很多資料散落在各處,可以把邏輯上可以劃分的資料放到一類中。
做法:使用Eclipse 選中欄位,選擇Refactory -> Extract Class
把所有選中欄位提到新類中,可以選擇建立檔案也可以使內部類

7.4 Inline Class(將類內聯化)
動機:類中沒有太多行為,與Extract class相反。

7.5 Hide Delegate(隱藏“委託關係”)
動機:通過“委託關係”,降低類之間的耦合。

7.6 Remove MiddleMan(移除中間人)
與7.5相反

7.7 Introduce Foreign Method(引入外加函數)
動機:函數的所有參數都是使用同一個資料對象的值,乾脆直接把資料對象傳進入,由函數內部


7.8 Introduce Local Extension(引入本地擴充)
動機:有些無法直接修改源碼的地方需要添加新的支援。
做法:繼承,然後填加功能。




第八章 重新組織資料


8.1 Self Encapsulate Field(自封裝值域)
動機:是直接使用欄位還是添加setter/getter總是爭論不休,建議直接使用欄位,當必須使用setter/getter時通過此模式自動改變。
做法:
Eclipse 重構工具可以自動完成此類操作。
Eclipse 中選中屬性,選擇Refactor -> Encapsulate Filed。

1. 設定getter/setter名稱
2. 使用此欄位處如何修改,use setter and getter(使用set與get方法替換引用、keep field refrence 保持原有欄位引用方式不變) -> OK
3. Insert new method after 插入位置

8.2 Replace Data Value with Object(以對象取代資料值)
動機:開發初期可能僅需要簡單的資料項目就可以搞定,隨著開發的進行線管資料項目越來越多,此時可以把資料值變成對象。
做法:
Eclipse 重構工具可以自動完成此類操作。
Eclipse 在需要抽取欄位的類中,選擇Refactor -> Extract Class 。
1. Class name指定新資料名稱
2. Destination 新建立類檔案,還是使用內部類形式
3. Select fields for extracted class 可以勾選抽取欄位,右側Edit可以編輯類型與欄位名
4. Field name 指定當前類中使用此新資料對象的欄位名。


8.3 Change Value to Reference (將值改為引用對象)
動機:
做法:

8.4 Change Reference to Value(將引用對象改為值對象)

8.5 Replace Array with Object(以對象取代數組)
動機:
做法:
          String[] person = new String[3];
          person[0] = "18";
          person[1] = "name";


修改後效果

8.6 DuplicateObservedData(複製“被監視資料”)
GUI多處顯示的值有關聯或者相同(把這些資料放置到一處)

8.7 ChangeUnidirectionalAssociationtoBidirectional(將單向關聯改為雙向關聯)
A引用B,希望修改為A引用B,B也引用A

8.8 ChangeBidirectionalAssociationtoUnidirectional(將雙向關聯改為單向關聯)
與8.7相反

8.9 ReplaceMagicNumberwithSymbolicConstant(以字面常量取代魔法數)
動機:魔法數字就是直接使用數字,存在的問題是,其他人不知道這個魔法數字是什麼意思,為什麼必須是這個數字,可能多處使用同樣邏輯的魔法數字,僅修改一處不會可能會忘記其他地方的修改。
做法:
Eclipse 重構工具可以自動完成此類操作。
Eclipse 中 選中需要抽取為常量的魔法數字,這裡是選中數字30,選擇Refactor -> Extract Constant(提取常量、把任意位置的字串或者數字抽取為一個靜態全域常量。所有使用此字元或者數位也會相應的被替換為使用常量。)

1. Constant name 設定名稱
2. Access modifier 設定存取權限
3. Replace all occurrences of the selected expression with references to the constant 如果勾選,會自動替換所以選中數位地方為此常量
4. Qualify constant references with type name 是否使用類型名限定常量引用


8.10 EncapsulateField(封裝欄位)
沒看出與 “8.1 Self Encapsulate Field(自封裝值域)” 有啥區別

8.11 EncapsulateCollection(封裝集合)
集合(列表、數組)函數不建議提供setter/getter, 前者會直接覆蓋掉整個集合,而且不方便反向尋找。後者直接獲得了所有集合的控制權。
建議修改為add/remove函數來間接操作集合。

8.12 ReplaceRecordwithDataClass(以資料類取代記錄)
把邏輯上一種類型的所有資料,封裝到一個新類中。

8.13 Replace Type Code with Class(以類取代類型碼)

8.14 ReplaceTypeCodewithSubclasses(以子類取代類型碼)

8.15 以State/Strategy取代識別碼
動機:以State Object (專門用來描述狀態的對象)取代type code
做法
1. 使用Self Encapsulate Filed 將type code自我封裝起來。
2. 建立一個class,根據type code用途命名。這就是State Object
3. 為新建立的class添加subclasses,每個subclasses對應一個type code
4. 在supperclass中建議一個抽象的查詢函數,用於返回type code。每個subclass中覆寫此函數,返回確切type code。
5. 編譯
6. 在source class中建立一個值域,用以儲存建立state object。
7. 調整source class中負責查詢type code的函數,將查詢動作轉寄給state object
8. 編譯,測試。


State 模式

8.16 Replace Subclass with Fields(以值域取代子類)
動機:如果每個子類中都返回常量,使用介面與多個子類已經多大意義。
做法:





第九章 簡化條件運算式

9.1 Decompose Conditional(分解條件運算式)
動機:判斷過多通常導致可讀性下降
做法:把if判斷中的條件抽取為方法

9.2 Consolidate Conditional Expression(合并條件運算式)
動機:有時發現一串條件檢查,檢查條件各不相同,但是最終行為卻一致。
做法:合并多個判斷,返回相同的值。

9.3 Consolidate Duplicate Conditional Fragments(合并重複的條件片段)
動機:如果if與else 中都執行的代碼,為何不乾脆放到if與else的外面?

9.4 Remove Control Flag(移除控制標記)
動機:Java依然支援條件陳述式中的標記,雖然不太常用的,但是如果使用會導致程式很難理解。

9.5 Replace Nested Conditional with Guard Clauses(以衛語句取代嵌套條件運算式)
動機:如果兩條分支都是正常行為,就應該使用if else 。但是如果某些條件極其罕見,就應該單獨檢查改條件,然後直接返回。這種通常稱為(衛語句guard clauses)
可以通過直接判斷返回的形式,檢查if嵌套的層級。

9.6 Replace Conditiona lwith Polymorphism(以多態取代條件運算式)??
把swtich修改為多態形式
動機:多態最根本的好處是:如果你需要根據對象的不同類別而採取不同的行為,多態使你不必編寫明顯的條件式。

9.7 Introduce Null Object(引入Null對象)
動機:很多地方判斷某個對象是否為空白,為空白如何處理,不為空白如何處理。乾脆判斷一次,如果為空白返回一個null object,由其內部為所有欄位賦予初始值,這樣不會導致異常,也不需要太多if(value == null)的判斷。

9.8 Introduce Assertion(引入斷言)
動機:檢查一定必須為真的條件。不要濫用,可以在編譯的時候通過指令碼刪除所有斷言。









第十章 簡化函數調用

10.1 Rename Method(函數改名)
動機:為一個方法起一個好的名字便於程式的理解。可以通過Eclipse outline視圖查看方法,像讀文章一樣。
做法:使用Eclipse 選中方法名,選擇Refactory -> Rename或者使用快速鍵Alt + Shift + R
可以對任意變數、類、方法、包名、檔案夾進行重新命名,並且所有使用到的地方會統一進行修改。

10.2 Add Parameter(添加參數)
10.3 Remove Parameter(移除參數)
動機:隨著系統的開發,添加與移除參數,或者修改參數的位置都是常見的重構。原有參數不能滿足現有需求,或者一些參數並未使用到
做法:使用Eclipse 選中方法名,選擇Refactory -> Change Method SignatureAlt + Shift + C或者使用快速鍵
對方法進行操作,可以修改方法名、存取權限、增加刪除方法參數、修改參數順序、添加方法異常

10.4 Separate Query from Modifier(將查詢函數和修改函數分離)
動機:將查詢結果緩衝下來,後續重複查詢就可以大大加快速度。

10.5 Parameterize Method(令函數攜帶參數)
動機:多個函數執行的流暢一樣,但是每個可能因為僅修改某個值,可以把這些值抽取到一個參數上,然後多處複用此方法傳入不同參數。

10.6 Replace Parameter with Explicit Methods(以明確函數取代參數)
動機:如果函數中需要通過參數判斷做哪些行為,乾脆為這個參數再建立一個新的函數進行處理。

10.7 Preserve Whole Object(保持對象完整)
動機:函數參數用到同一個對象的多個參數,如果增加或者刪除參數的話,需要對所有使用到的地方進行修改。
做法:把所有參數替換為此對象,函數內部從此對象上取值。

10.8 Replace Parameter with Methods(以函數取代參數)
動機:如果函數的參數可通過其他函數擷取到,沒必要把它作為函數的參數傳入,直接在函數內部調用其想要當參數傳入的函數即可。
過長的參數列表,不利於維護與理解。


10.9 Introduce ParameterObject(引入參數對象)
動機:把多個參數,如果是可以抽取為一種類型的,把這些欄位都放入建立資料類中,然後進傳遞此資料類即可。


10.10 Remove Setting Method(移除設值函數)
動機:一些參數並不需要被改變,可以刪除其setter函數達到效果。


10.11 Hide Method(隱藏函數)
動機:把某些資料隱藏起來,某些行為其他地方不能觸發。可以把函數的許可權調低。public -> private


10.12 Replace Constructor with Factory Method(以工廠函數取代建構函式)
動機:取消以type code建立對象


10.13 Encapsulate Downcast(封裝向下轉型)
動機:返回Object然後在向下轉型,如果可以直接返回固定的類型。


10.14 Replace Error Code with Exception(以異常取代錯誤碼)
動機:一些異常直接返回數值,為何不乾脆throw new exception?


10.15 Replace Exception with Test(以測試取代異常)
動機:異常不能成為條件檢查的替代品






第十一章 處理概括關係


11.1 PullUpField(欄位上移)
11.2 PullUpMethod(函數上移)
11.3 PullUpConstructorBody(建構函式本體上移)
11.4 PushDownMethod(函數下移)
11.5 PushDownField(欄位下移)
11.6 ExtractSubclass(提煉子類)


第十二章 大型重構


12.1 Tease Apart Inheritance(梳理並分解繼承體系) 
建立兩個繼承體系,並通過委託關係讓其中一個可以調用另外一個。

12.2 Convert Procedural Design to Objects(將過程化設計轉化為對象設計) 
典型情況:class中有著長長的過程函數和極少的資料,以及所謂的亞資料對象,處了資料訪問函數外沒有其他任何函數。

12.3 Separate Domain from Presentation(將領域和表述/顯示分離) 
將domain logic(領域邏輯)分離出來,為它們建立獨立的domain classes
動機:MVC模式,將使用者介面代碼(view) 和 領域邏輯(model 模型)分離了。

12.4 Extract Hierarchy(提煉繼承體系) 
動機:設計之初僅需要一個類完成功能 ,實現過程中發現一個類中有2,3個功能。可以把這些新增的功能作為子類實現。




第十三章 重構,複用與現實 


13.1 現實的檢驗 
只有已經開發完成一版,再次基礎上新增功能,才會強烈的對重構的需求。


13.2 為什麼開發人員不願意重構他們的程式 
1. 不知道如何重構
2. 短視,工期壓力比較大
3. 代碼重構是新工作量
4. 重構可能引入BUG


13.3 再論現實的檢驗 


13.4 重構的資源和參考資料 


13.5 從重構聯想到軟體複用和技術傳播 


《重構》讀書筆記 與 Eclipse 重構功能使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.