重構(Refactoring)技巧讀書筆記 之二

重構(Refactoring)技巧讀書筆記 之二<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

General Refactoring Tips, Part 2

?

本文繼續《重構(Refactoring)技巧讀書筆記 之一》,重構的確是未來軟件工程師需要掌握的一項技能。目前一些支持.Net的重構工具,如ReSharper for VS.Net v1.0Borland Together for VS.Net v2.0VS.Net 2005等,只能支持一些有限的、比較簡單的重構策略。大量的重構策略需要軟件工程師清晰的了解,人工為主,運用重構工具輔助進行。(注:本文重構策略的名稱及其大部分內容來自《重構-改善既有代碼的設計》一書,Martin Fowler 著,侯捷等譯)。

下面的內容延續上一節的內容,其中提及的一些代碼壞味道Bad Smell in Codes及其重構策略相對而言要比較麻煩一些。

?

一、代碼壞味道(Bad Smell in Codes)及其重構策略

5Divergent Change(發散式變化)

現象:當某個Class因為外部條件的變化或者客戶提出新的功能要求等時,每次修改要求我們更新Class中不同的方法。不過這種情況只有在事后才能覺察到,因為修改都是在事后發生的么(廢話)。

重構策略:將每次因同一條件變化,而需要同時修改的若干方法通過Extract Class將它們提煉到一個新Class中。實現目標是:每次變化需要修改的方法都在單一的Class中,并且這個新的Class內所有的方法都應該與這個變化相關。

?

6Shotgun Surgery(霰彈式修改)

現象:當外部條件發生變化時,每次需要修改多個Class來適應這些變化,影響到很多地方。就像霰彈一樣,發散到多個地方。

重構策略:使用Move MethodMove FieldClass中需要修改的方法及成員變量移植到同一個Class中。如果沒有合適的Class,則創建一個新Class。實現目標是,將需要修改的地方集中到一個Class中進行處理。

?

比較Divergent Change(發散式變化)和Shotgun Surgery(霰彈式修改):

前者指一個Class受到多種外部變化的影響。而后者指一種變化需要影響到多個Class需要修改。都是需要修理的對象。

?

7Feature Envy(依戀情結)

現象:Class中某些方法“身在曹營心在漢”,沒有安心使用Class中的成員變量,而需要大量訪問另外Class中的成員變量。這樣就違反了對象技術的基本定義:將數據和操作行為(方法)包裝在一起。

重構策略:使用Move Method將這些方法移動到對應的Class中,以化解其“相思之苦”,讓其牽手。

?

8Data Clumps(數據泥團)

現象:指一些相同數據項目(Data Items),如Class成員變量和方法中參數列表等,在多個Class中多次出現,并且這些數據項目有其內在的聯系。

重構策略:通過使用Introduce Parameter Object(創建新的參數對象取代這些參數)或Preserve Whole Object(使用已存在的對象取代這些參數),實現使用對象代替Class成員變量和方法中參數列表,清除數據泥團,使代碼簡潔,也提高維護性和易讀性。

?

9Primitive Obsession(基本型偏執狂)

現象:在Class中看到大量的基本型數據項目(Data Item),如Employee類中有大量的數據成員,Employee#, FirstName, MiddleName, LastName, Address, State, City, Street, Zip, OfficePhone, CellPhone, Email……等等。

重構策略:使用Extract Class(提煉新類)或Preserve Whole Object(使用已存在的對象取代這些參數),實現使用對象代替基本型數據項目(Data Item)。如上述Employee類中就可分別提煉出EmployeeNameEmployeeContact兩個新類。

?

10Switch StatementsSwitch語句)

現象:同樣的Switch語句出現在不同的方法或不同的Class中,這樣當需要增加新的CASE分支或者修改CASE分支內語句時,就必須找到所有的地方,然后進行修改。這樣,就比較麻煩了。

重構策略:(1)首先采用Extract MethodSwitch語句提煉到一個獨立的函數。

(2)然后以Move Method搬移到需要多態性(Polymorphism)的Superclass里面或者是構建一個新的Superclass

(3)進一步使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy。這步就比較麻煩些,不過記住如下基本規則:這里一般有3Class分別為Source ClassSuperclassSubclass

Source Class

l???????? 使用Self Encapsulate Field,將Type Code成員變量封裝起來,也就是建立對應的Setter/Getter函數。

l???????? Source Class中增加一個Superclass類型的成員變量,用來存放Subclass實例對象。

l???????? Source Class中的Getter函數,通過調用SuperclassAbstract Query函數來完成。

l???????? Source Class中的Setter函數,通過調用Superclass中的Static工廠化方法來獲取合適的Subclass實例對象。

?

Superclass

新建的一個Class(注:就是上面通過Move Method搬移生成的Superclass),根據Type Code的用途命名該Class,作為Superclass

l???????? Superclass中建立一個Abstract Query函數,用來獲取SubclassType Code

l???????? Superclass中創建Static工廠化方法生產對應的Subclass對象,這里會存在一個Switch語句(不要再動腦筋來重構這個Switch語句了,這個Switch語句不會在多處重復存在,并且這里用于決定創建何種Subclass對象,這是完全可以接受的)。

?

Subclass

l???????? 根據每一個Switch/Type分支,建立對應的Subclass,并且Subclass的命名可以參考Switch/Type分支的命名。

l???????? 在每一個Subclass中重載SuperclassAbstract Query函數,返回特定的Type Code

(4)現在Superclass仍然存在Switch分支,是時候輪到Replace Conditional with Polymorphism上場了。具體而言,就是在每一個Subclass中創建重載方法(注:該方法是Superclass中含有Switch語句的方法),并將SuperclassSwitch語句對應的Case分支剪切過來。最后將Superclass中該方法初象化Abstract,并清除Switch語句及其所有的Case分支。

這樣就完成了整個重構過程,這個比較麻煩。

?

注:并不是一看到Switch語句及CASE分支,就馬上/偏執狂采用上述重構策略進行重構,畫蛇添足或吃虧不討好(個人觀點)。一般而言,只有看到多處出現相同的Switch語句時,才應該考慮進行重構。

?

References:

1, Rickie, 重構(Refactoring)技巧讀書筆記 之一

轉載于:https://www.cnblogs.com/rickie/archive/2004/10/04/48859.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/277366.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/277366.shtml
英文地址,請注明出處:http://en.pswp.cn/news/277366.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

史上最全的Angular.js 的學習資源

Angular.js 的一些學習資源 基礎 官方&#xff1a; http://docs.angularjs.org angularjs官方網站已被墻&#xff0c;可看 http://www.ngnice.com/&#xff1b;官方zip下載包 http://best.factj.com/dolymood/angular-packages&#xff0c;已增加docs服務&#xff0c;輸入地址即…

BMP位圖之8位位圖(三)

起始結構 typedef struct tagBITMAPFILEHEADER { WORD bfType; //類型名&#xff0c;字符串“BM”&#xff0c; DWORD bfSize; //文件大小 WORD bfReserved1; //保留字 WORD bfReserved2; //保留字 DWORD bfOffBits; //實際位圖數據的偏移字節數&#xff0c;即前三個部分長度之…

DNN 漢化中的問題????

今天看到了一份已經漢化過的DNN但是比較奇怪&#xff0c;當第一次運行后我所指定的新數據庫中并沒有添加新的內容&#xff0c;但是網站上的確是已經漢化過了的&#xff0c;不知道它把漢化的內容放到了哪里&#xff1f;&#xff1f;&#xff1f; 另外他所漢化界面的地方&#x…

php 打印對象詳細信息,php打印顯示數組與對象的函數詳解

php打印顯示數組與對象的函數詳解發布于 2014-11-17 18:55:49 | 699 次閱讀 | 評論: 0 | 來源: 網友投遞PHP開源腳本語言PHP(外文名: Hypertext Preprocessor&#xff0c;中文名&#xff1a;“超文本預處理器”)是一種通用開源腳本語言。語法吸收了C語言、Java和Perl的特點&…

ios開發-調用系統自帶手勢

在 iPhone 或 iPad 的開發中&#xff0c;除了用 touchesBegan / touchesMoved / touchesEnded 這組方法來控制使用者的手指觸控外&#xff0c;也可以用 UIGestureRecognizer 的衍生類別來進行判斷。用 UIGestureRecognizer 的好處在于有現成的手勢&#xff0c;開發者不用自己計…

Node.js 事件循環

Node.js 事件循環 Node.js 是單進程單線程應用程序&#xff0c;但是因為 V8 引擎提供的異步執行回調接口&#xff0c;通過這些接口可以處理大量的并發&#xff0c;所以性能非常高。 Node.js 幾乎每一個 API 都是支持回調函數的。 Node.js 基本上所有的事件機制都是用設計模式中…

全國翻譯專業資格(水平)考試

http://www.spta.gov.cn/moreksxx.jsp?lmCodeA02010205轉載于:https://www.cnblogs.com/Danilo/archive/2004/10/31/58821.html

linux文件句柄,【LINUX】使用lsof處理文件恢復、句柄以及空間釋放問題

曾經在生產上遇到過一個df 和 du出現的結果不一致的問題&#xff0c;為了排查到底是哪個進程占用了文件句柄&#xff0c;導致空間未釋放&#xff0c;首先在linux上面&#xff0c;一切皆文件&#xff0c;這個問題可以使用lsof這個BT的命令來處理(這個哈還可以來查詢文件句柄泄露…

android天氣查詢(二)之網絡json數據的獲取

前面一篇文章介紹了如何使用ksoap獲取天氣信息&#xff0c;但是使用的網絡資源受到了限制&#xff0c;所以我們這里會采用第二種方法&#xff0c;可以無限制的獲取。http://m.weather.com.cn/data/101010100.html 但是對應的101010100(北京)我們怎么獲取呢&#xff0c;還有就是…

累.....

今天我真的蔫了&#xff0c;好累&#xff0c;腦子也好濁&#xff0c;但是還好&#xff0c;最終達到了預期的目的。我終于把henry的dataGrid實現了&#xff0c;犯了低級錯誤&#xff0c;和好多人討論&#xff0c;但最終還是henry解決的。那一刻&#xff0c;真的好爽&#xff0c;…

001-pro ant design 升級2.0后變更

一、更新點 1、目錄調整 2、本地代理服務器調整 roadhog→umi 配置方式 在這個config/config.js配置 "proxy": { "/api": { "target": "http://jsonplaceholder.typicode.com/", "changeOrigin": true, "pathRewrite&q…

linux cp 時 略過文件,CentOS下執行cp命令式提示略過文件夾

今天在CentOS下復制一個文件夾到另一個文件夾的時候cp ./res /usr 的時候出現了問題&#xff0c;提示我的是&#xff1a;cp略過了文件夾后來我找了一下在網上search了一下CP命令的用法&#xff1a;CP命令該命令的功能是將給出的文件或目錄拷貝到另一文件或目錄中&#xff0c;同…

屬性頁中的ON_UPDATE_COMMAND_UI

我前面翻譯了一篇文章簡單的談了一下在對話框處理ON_UPDATE_COMMAND_UI 消息。又在www.codeguru.com上看到在屬性頁中處理ON_UPDATE_COMMAND_UI 消息的方法和在對話框中稍有不同。兩者的處理大體上一樣。只是在屬性頁中還需要一個步驟。需要從CPropertySheet派生類&#xff0c;…

linux基礎命令rpm,rpm常用命令集合1

提要&#xff1a;RPM 是 Red Hat Package Manager 的縮寫&#xff0c;原意是Red Hat 軟件包管理&#xff1b;本文介紹RPM&#xff0c;并結合實例來解說RPM手工安裝、查詢等應用&#xff1b;正文&#xff1a;RPM包管理的用途&#xff1b;1、可以安裝、刪除、升級和管理軟件&…

hibernate詳解

Hibernate原理與應用 主要內容 1、引入 2、安裝配置 3、基本概念和CURD 4、HQL和Criteria 5、關聯映射 6、繼承映射 7、集合映射 8、懶加載 9、緩存 10、事務 11、其他 12、Hibernate不適合的場景 13、與JPA的集成(annotation方式) 14、最佳實踐 1、引入 模型不匹配(阻抗不匹配…

Csharp+Asp.net系列教程(四)

邁克老貓 來自&#xff1a;老貓的理想 本教程參考C#和ASP.NET程序設計教程撰寫&#xff0c;有什么不足之處請大家指出&#xff0c;或在老貓的理想BLOG留言。 這次簡述一下操作符 1.算術操作符 算術操作符包括加()、減(-)、乘(*)、除(/)和求余(%)。加減操作符…

linux 腳本 寫更新,用Shell寫的游戲客戶端更新腳本

#!/bin/sh########################################### 客戶端版本更新系統########################################### CLIENT_INIT_VERSION 客戶端新版本&#xff0c;默認是0# CLIENT_OLD_VERSION 客戶端舊版本(存放在VERSION_FILE指定的文件中)&#xff0c;當沒有時取CL…

Android Studio 環境搭建參考,jdk10javac命令提示不是內部或外部命令

https://blog.csdn.net/qq_33658730/article/details/78547789 win10下Android Studio和SDK下載、安裝和環境變量配置 http://yanmin99.com/ android-0基礎從入門到精通 環境變量ANDROID_HOMEE:\Program Files (x86)\Android\SdkJAVA_HOMEE:\Program Files\Java\jdk1.8.0_161TO…

報表引擎 - 數據模型

介紹 本文檔是報表模型的數據模型部分&#xff0c;說明平臺報表中涉及的報表數據相關 術語 名稱 說明 數據源 數據源是與數據存儲的連接。支持數據源適配 數據集 定義報表數據來源的一個二維表 參數 報表往往有參數&#xff0c;例如&#xff0c;日報表&#xff0c;當…

linux 刪舊內核,Ubuntu 刪除舊內核的方法

使用Ubuntu時如果系統里安裝了很多內核&#xff0c;會造成多于的啟動列表。想刪掉一些不用的內核方法如下方法一&#xff1a;首先就是使用如下命令&#xff0c;列出所有安裝的內核&#xff0c;下表中&#xff0c;帶有p_w_picpath的就是內核文件。從中選擇要卸載的包&#xff0c…