Refactoring
What Refacing:
重構(gòu)(Refactoring)就是在不改變軟件現(xiàn)有功能的基礎(chǔ)上,通過調(diào)整程序代碼改善軟件的質(zhì)量、性能,使其程序的設(shè)計模式和架構(gòu)更趨合理,提高軟件的擴(kuò)展性和維護(hù)性。
經(jīng)典的Refacing Definition:
(1)Refactoring means rewriting existing source code with the intent of improving its design rather than changing its external behavior. The focus of refactoring is on the structure of the source code, changing the design to make the code easier to understand, maintain, and modify. - 來自Borland Together提供的文檔,覺得這個定義很清晰明了。
(2)重構(gòu)是這樣一個過程:在不改變代碼外在行為的前提下,對代碼做出修改,已改進(jìn)程序的內(nèi)部結(jié)構(gòu)。-來自Martin Fowler的定義。
Refactoring (noun): a change made to the internal structure of software to make iteasier to understand andcheaper to modifywithout changing its observable behavior.
Refactor (verb): to restructure softwareby applying a series of refactoringswithout changing its observable behavior.
Why Refacing:
Improves the design of software
Makes software easier to understand - leads to higher levels of understanding
Helps to find bugs
Helps to be more effective at writing robust code
Helps to program faster
1、·持續(xù)偏糾和改進(jìn)軟件設(shè)計。
2、·使代碼更易為人所理解。
3、·幫助發(fā)現(xiàn)隱藏的代碼缺陷。
4、·從長遠(yuǎn)來看,有助于提高編程效率。
When Refacing:Three strikes and you refactor.
When you add functionality.
When you need to fix a bug.
When you do a code review.
1、·代碼中存在重復(fù)的代碼。
2、·過大的類和過長的方法。
3、·牽一毛而需要動全身的修改。
4、·類之間需要過多的通訊。
5、·過度耦合的信息鏈。
6、·不完美的設(shè)計。
7、·缺少必要的注釋。
不要當(dāng)你需要新的功能的時候,或者原來的程序出了Bug,你才想起重構(gòu)。
總結(jié):代碼重構(gòu)在你開始寫代碼就是被要考慮進(jìn)去的,邊寫代碼邊重構(gòu)。
What makes programs hard to work with?
Kent Beck:
We want programs:
easy to read,
have all logic specified in one and only place,
do not allow changes to endanger existing behavior,
allow conditional logic to be expressed as simply as possible.
Refactoring and Design
Refactoring and Performance
Refactoring will make software run more slowly, but it also makes the software more easy for performance tuning. The secret to fast software is towrite tunable software first andthen to tune it for sufficient speed.
Run a profiler to find the performance hot spots.
Focus on these performance hot spots and optimize them.
Rerun the profiler, if the performance does not improve, back out the change.
Continue the process until the performance satisfies your users.
How Refacing:
減少代碼壞味道(Bad Smell in Codes)的重構(gòu)策略
1.Duplicated Code 盡量消除重復(fù)的代碼,將它們合而為一 Do Not Repeat Yourself.
根據(jù)重復(fù)的代碼出現(xiàn)在不同的地方,分別采取不同的重構(gòu)的策略:
在同一個Class的不同地方:通過采用重構(gòu)工具提供的Extract Method功能提煉出重復(fù)的代碼, 然后在這些地方調(diào)用上述提煉出方法。
在不同Subclasses中:通過Extract Method提煉出重復(fù)的代碼,然后通過Pull Up Method將該方法移動到上級的Super class內(nèi)。
在沒有關(guān)系的Classes中:通過對其中一個使用Extract Class將重復(fù)的代碼提煉到一個新類中,然后在另一個Class中調(diào)用生成的新類,消除重復(fù)的代碼。
?
2.Long Method 拆解過長的函數(shù)
過長的函數(shù)在我們的日常代碼中經(jīng)??梢?#xff0c;在C#中常通過#region #endregion區(qū)隔為不同的功能區(qū)域。
重構(gòu)策略:通過Extract Method將過長的函數(shù)按照功能的不同進(jìn)行適當(dāng)拆解為小的函數(shù),并且給這些小函數(shù)一個好名字。通過名字來了解函數(shù)提供的功能,提高代碼的理解性。
?
3.Large Class 拆解過大的類
過大的類也經(jīng)常見到,特別是類中含有大量的成員變量。
重構(gòu)策略:通過Extract Class將一些相關(guān)成員變量移植到新的Class中,如Employee類,一般會包含有聯(lián)系方式的相關(guān)屬性(電話, Mobile,地址,Zip等等),則可以將這些移植到新的EmployeeContact類中。
?
4.Long Parameter List 過長的參數(shù)列
過長的參數(shù)列的主要問題是難以理解,并且難以維護(hù)。如果要增加新的參數(shù)或者刪除某一參數(shù),易造成參數(shù)前后不一致。
重構(gòu)策略:如果可以通過向已存在的對象查詢獲取參數(shù),則可通過Replace Parameter with Method,移除參數(shù)列,通過在函數(shù)內(nèi)部向上述已存在的對象查詢來獲取參數(shù)。
如果參數(shù)列中若干參數(shù)是已存在對象的屬性,則可通過Preserve Whole Object將這些參賽替換為一個完整對象,這樣不僅提高代碼的可讀性,同時已易于代碼今后的維護(hù)。
另外,還可以將若干不相關(guān)的參數(shù),使用Introduce Parameter Object來創(chuàng)建一個新的參數(shù)類。不過,我個人覺得如果這些情況過多的話,會產(chǎn)生很多莫名其妙的參數(shù)類了,反而降低代碼的可讀性。
5.Divergent Change(發(fā)散式變化)
現(xiàn)象:當(dāng)某個Class因為外部條件的變化或者客戶提出新的功能要求等時,每次修改要求我們更新Class中不同的方法。不過這種情況只有在事后才能覺察到,因為修改都是在事后發(fā)生的么(廢話)。
重構(gòu)策略:將每次因同一條件變化,而需要同時修改的若干方法通過Extract Class將它們提煉到一個新Class中。實(shí)現(xiàn)目標(biāo)是:每次變化需要修改的方法都在單一的Class中,并且這個新的Class內(nèi)所有的方法都應(yīng)該與這個變化相關(guān)。
?
6.Shotgun Surgery(霰彈式修改)
現(xiàn)象:當(dāng)外部條件發(fā)生變化時,每次需要修改多個Class來適應(yīng)這些變化,影響到很多地方。就像霰彈一樣,發(fā)散到多個地方。
重構(gòu)策略:使用Move Method和Move Field將Class中需要修改的方法及成員變量移植到同一個Class中。如果沒有合適的Class,則創(chuàng)建一個新Class。實(shí)現(xiàn)目標(biāo)是,將需要修改的地方集中到一個Class中進(jìn)行處理。
?
比較Divergent Change(發(fā)散式變化)和Shotgun Surgery(霰彈式修改):
前者指一個Class受到多種外部變化的影響。而后者指一種變化需要影響到多個Class需要修改。都是需要修理的對象。
?
7.Feature Envy(依戀情結(jié))
現(xiàn)象:Class中某些方法“身在曹營心在漢”,沒有安心使用Class中的成員變量,而需要大量訪問另外Class中的成員變量。這樣就違反了對象技術(shù)的基本定義:將數(shù)據(jù)和操作行為(方法)包裝在一起。
重構(gòu)策略:使用Move Method將這些方法移動到對應(yīng)的Class中,以化解其“相思之苦”,讓其牽手。
?
8.Data Clumps(數(shù)據(jù)泥團(tuán))
現(xiàn)象:指一些相同數(shù)據(jù)項目(Data Items),如Class成員變量和方法中參數(shù)列表等,在多個Class中多次出現(xiàn),并且這些數(shù)據(jù)項目有其內(nèi)在的聯(lián)系。
重構(gòu)策略:通過使用Introduce Parameter Object(創(chuàng)建新的參數(shù)對象取代這些參數(shù))或Preserve Whole Object(使用已存在的對象取代這些參數(shù)),實(shí)現(xiàn)使用對象代替Class成員變量和方法中參數(shù)列表,清除數(shù)據(jù)泥團(tuán),使代碼簡潔,也提高維護(hù)性和易讀性。
?
9.Primitive Obsession(基本型偏執(zhí)狂)
現(xiàn)象:在Class中看到大量的基本型數(shù)據(jù)項目(Data Item),如Employee類中有大量的數(shù)據(jù)成員,Employee#, FirstName, MiddleName, LastName, Address, State, City, Street, Zip, OfficePhone, CellPhone, Email……等等。
重構(gòu)策略:使用Extract Class(提煉新類)或Preserve Whole Object(使用已存在的對象取代這些參數(shù)),實(shí)現(xiàn)使用對象代替基本型數(shù)據(jù)項目(Data Item)。如上述Employee類中就可分別提煉出EmployeeName和EmployeeContact兩個新類。
?
10.Switch Statements(Switch語句)
現(xiàn)象:同樣的Switch語句出現(xiàn)在不同的方法或不同的Class中,這樣當(dāng)需要增加新的CASE分支或者修改CASE分支內(nèi)語句時,就必須找到所有的地方,然后進(jìn)行修改。這樣,就比較麻煩了。
重構(gòu)策略:(1)首先采用Extract Method將Switch語句提煉到一個獨(dú)立的函數(shù)。
(2)然后以Move Method搬移到需要多態(tài)性(Polymorphism)的Superclass里面或者是構(gòu)建一個新的Superclass。
(3)進(jìn)一步使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy。這步就比較麻煩些,不過記住如下基本規(guī)則:這里一般有3個Class分別為Source Class、Superclass和Subclass。
Source Class:
l???????? 使用Self Encapsulate Field,將Type Code成員變量封裝起來,也就是建立對應(yīng)的Setter/Getter函數(shù)。
l???????? 在Source Class中增加一個Superclass類型的成員變量,用來存放Subclass實(shí)例對象。
l???????? 在Source Class中的Getter函數(shù),通過調(diào)用Superclass的Abstract Query函數(shù)來完成。
l???????? 在Source Class中的Setter函數(shù),通過調(diào)用Superclass中的Static工廠化方法來獲取合適的Subclass實(shí)例對象。
?
Superclass:
新建的一個Class(注:就是上面通過Move Method搬移生成的Superclass),根據(jù)Type Code的用途命名該Class,作為Superclass。
l???????? 在Superclass中建立一個Abstract Query函數(shù),用來獲取Subclass的Type Code。
l???????? 在Superclass中創(chuàng)建Static工廠化方法生產(chǎn)對應(yīng)的Subclass對象,這里會存在一個Switch語句(不要再動腦筋來重構(gòu)這個Switch語句了,這個Switch語句不會在多處重復(fù)存在,并且這里用于決定創(chuàng)建何種Subclass對象,這是完全可以接受的)。
?
Subclass:
l???????? 根據(jù)每一個Switch/Type分支,建立對應(yīng)的Subclass,并且Subclass的命名可以參考Switch/Type分支的命名。
l???????? 在每一個Subclass中重載Superclass的Abstract Query函數(shù),返回特定的Type Code。
(4)現(xiàn)在Superclass仍然存在Switch分支,是時候輪到Replace Conditional with Polymorphism上場了。具體而言,就是在每一個Subclass中創(chuàng)建重載方法(注:該方法是Superclass中含有Switch語句的方法),并將Superclass中Switch語句對應(yīng)的Case分支剪切過來。最后將Superclass中該方法初象化Abstract,并清除Switch語句及其所有的Case分支。
這樣就完成了整個重構(gòu)過程,這個比較麻煩。
11.Parallel Inheritance Hierarchies(平行繼承體系)
現(xiàn)象:為某個class增加一個subclass時,也必須為另一個class相應(yīng)增加一個subclass。重構(gòu)策略: 在一個class繼承體系的對象中引用(refer to)另一個class繼承體系的對象,然后運(yùn)用Move Method和Move Field將被引用class中的一些方法和成員變量遷移宿主class中,消除被引用class的繼承體系(注:這種平行繼承體系好象比較少見也)。
?
12.Lazy Class(冗贅類)
現(xiàn)象:某一些class由于種種原因,現(xiàn)在已經(jīng)不再承擔(dān)足夠責(zé)任,有些多余了。如同國有企業(yè)冗余人員一樣,需要下崗了。
重構(gòu)策略:通過Collapse Hierarchy,將這些冗余的class合并到superclass或subclass中,或者通過Inline Class(與Extract Class相反),將這些冗余class中的所有Method/Field遷移到其他相關(guān)的class中。
?
13.Speculative Generality(夸夸其談未來性)
現(xiàn)象:系統(tǒng)中出現(xiàn)一些無用的abstract class,或者非必要的delegation(委托),或者多余的參數(shù)等等。
重構(gòu)策略:分別使用Collapse Hierarchy合并abstract class,使用Inline Class移除非必要的delegation,使用Remove Parameter刪除多余的參數(shù)。
?
14.Temporary Field(令人迷惑的暫時值域)
現(xiàn)象:class中存在一些Field,這些Field只在某種非常特定的情況下需要。
重構(gòu)策略:通過Extract Class將這些孤獨(dú)的Field及其相關(guān)的Method移植的一些新的Class中。提煉出來的新Class可能沒有任何抽象意義,只是提供Method的調(diào)用,這些新Class一般稱為Method Object。
?
15.Message Chains(過度耦合的消息鏈)
現(xiàn)象:向一個對象請求另一個對象,然后再向后者請求另一個對象,……,這就是Message Chain,意味著Message Chain中任何改變,將導(dǎo)致Client端不得不修改。
重構(gòu)策略:通過Hide Delegate(隱藏委托關(guān)系)消除Message Chain,具體做法是在Message Chain的任何地方通過Extract Method建立一個簡單委托(Delegation)函數(shù),來減少耦合(Coupling)。
?
16.Middle Man(中間轉(zhuǎn)手人)
現(xiàn)象:過度運(yùn)用delegation,某個/某些Class接口有一半的函數(shù)都委托給其他class,這樣就是過度delegation。
重構(gòu)策略:運(yùn)用Remove Middle Man,移除簡單的委托動作(也就是移除委托函數(shù)),讓client直接調(diào)用delegate受托對象。和上面的Hide Delegate(隱藏委托關(guān)系)剛好相反的過程。
?
由于系統(tǒng)在不斷的變化和調(diào)整,因此[合適的隱藏程度]這個尺度也在相應(yīng)的變化,Hide Delegate和Remove Middle Man重構(gòu)策略可以系統(tǒng)適應(yīng)這種變化。
?
另外,可保留一部分委托關(guān)系(delegation),同時也讓Client也直接使用delegate受托對象。
?
17.Inappropriate Intimacy(狎昵關(guān)系)
現(xiàn)象:兩個Class過分親密,彼此總是希望了解對方的private成分。
重構(gòu)策略:可以采用Move Method和Move Field來幫助他們劃清界限,減少他們之間親密行為?;蛘哌\(yùn)用Change Bidirectional Association to Unidirectional,將雙向關(guān)聯(lián)改為單向,降低Class之間過多的依存性(inter-dependencies)?;蛘咄ㄟ^Extract Class將兩個Class之間的共同點(diǎn)移植到一個新的Class中。
?
18.Alternative Classes with Different Interfaces(異曲同工的類)
現(xiàn)象:兩個函數(shù)做相同的事情,卻有不同的signature。
重構(gòu)策略:使用Rename Method,根據(jù)他們的用途來重命名。另外,可以適當(dāng)運(yùn)用Move Method遷移某些行為,使Classes的接口保持一致。
?
19.Incomplete Library Class(不完美的程序庫類)
現(xiàn)象:Library Class(類庫)設(shè)計不是很完美,我們需要添加額外的方法。
重構(gòu)策略:如果可以修改Library Class的Source Code,直接修改最好。如果無法直接修改Library Class,并且只想修改Library Class內(nèi)的一兩個函數(shù),可以采用Introduce Foreign Method策略:在Client Class中建立一個函數(shù),以外加函數(shù)的方式來實(shí)現(xiàn)一項新功能(一般而言,以server class實(shí)例作為該函數(shù)的第一個參數(shù))。
?
如果需要建立大量的額外函數(shù),可應(yīng)該采用Introduce Local Extension:建立一個新class,使它包含額外函數(shù),并且這個class或者繼承或者wrap(包裝)source class。
?
20.Data Class(純稚的數(shù)據(jù)類)
現(xiàn)象:Data Class指:一些Class擁有Fields,以及用來訪問Fields的getter/setter函數(shù),但是沒有其他的功能函數(shù)。(感覺這些Data Class如同Entity Class或Parameter Class,用來傳遞參數(shù),我認(rèn)為這種情況下沒有必要重構(gòu)。)
重構(gòu)策略:找出其他class中訪問Data Class中的getter/setter的函數(shù),嘗試以Move Method將這些函數(shù)移植到Data Class中,實(shí)現(xiàn)將數(shù)據(jù)和操作行為(方法)包裝在一起,也讓Data Class承擔(dān)一定的責(zé)任(方法)。
?
21.Refused Bequest(被拒絕的遺贈)
現(xiàn)象:Subclass不想或不需要繼承superclass的部分函數(shù)和Field。
重構(gòu)策略:為subclass新建一個兄弟(sibling class),再運(yùn)用Push Down Method和Push Down Field將superclass中的相應(yīng)函數(shù)和Field下推到兄弟class,這樣superclass就只包含subclass共享的東西了。其實(shí),也就是將superclass中一些與特定的函數(shù)和Field放到特定的subclass中,superclass中僅包含subclass共享的函數(shù)和Field。
?
如果不想修改superclass,還可以運(yùn)用Replace Inheritance with Delegation來達(dá)到目的。也就是以委托取代繼承,在subclass中新建一個Field來保存superclass對象,去除subclass對superclass的繼承關(guān)系,委托或調(diào)用superclass的方法來完成目的。
?
22.Comments(過多的注釋)
現(xiàn)象:(暈倒,這個也要重構(gòu),Remove掉所有的Comments嗎?不是。)當(dāng)代碼中出現(xiàn)一段長長的注釋,一般是由于代碼比較糟糕,需要進(jìn)行重構(gòu),除去代碼的壞味道。
重構(gòu)策略:通過上面提及的各種重構(gòu)策略,將代碼的壞味道去除,使注釋變成多余。
如果需要注釋/解釋一段代碼做了什么,則可以試試Extract Method,提取出一個獨(dú)立的函數(shù),讓函數(shù)名稱解釋該函數(shù)的用途/功能。另外,如果覺得需要注釋來說明系統(tǒng)的某些假設(shè)條件,
也可嘗試使用Introduce Assertion(引入斷言),來明確標(biāo)明這些假設(shè)。
?
當(dāng)你感覺需要撰寫注釋時,請先嘗試重構(gòu),試著讓所有的注釋都變得多余。?
注:并不是一看到Switch語句及CASE分支,就馬上/偏執(zhí)狂采用上述重構(gòu)策略進(jìn)行重構(gòu),畫蛇添足或吃虧不討好(個人觀點(diǎn))。一般而言,只有看到多處出現(xiàn)相同的Switch語句時,才應(yīng)該考慮進(jìn)行重構(gòu)。
Refactoring Practice:
1、When you find you have to add a feature to a program, and the program's code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.
2、Before you start refactoring, check that you have a solid suite of tests. These tests must be self-checking.
3、Refactoring changes the programs in small steps. If you make a mistake, it is easy to find the bug.
4、Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
5、Don't publish interfaces prematurely. Modify your code ownership policies to smooth refactoring.
6、Make sure all tests are fully automatic and that they check their own results.
7、A suite of tests is a powerful bug detector that decapitates the time it takes to find bugs.
8、Run your tests frequently. Localize tests whenever you compile—every test at least every day.
9、When you get a bug report, start by writing a unit test that exposes the bug.
10、It is better to write and run incomplete tests than not to run complete tests.
11、Think of the boundary conditions under which things might go wrong and concentrate your tests there.
12、Don't forget to test that exceptions are raised when things are expected to go wrong.
13、Don't let the fear that testing can't catch all bugs stop you from writing the tests that will catch most bugs.
1、把握全局,先了解業(yè)務(wù)
2、閱讀代碼,清除冗余代碼,重構(gòu)變量名等,刪除不一致或無效的注釋,補(bǔ)寫注釋,為下一步做準(zhǔn)備
3、將通用的代碼塊提升為方法
4、小步前進(jìn),隨時測試
5、重構(gòu)要隨時進(jìn)行
6、避免過度設(shè)計。模式是把雙刃劍。
最終的收獲:每個程序員都應(yīng)該不斷加強(qiáng)自己的編程思想,注重編程質(zhì)量。
1、 管理層不重視代碼書寫,認(rèn)為是體力勞動;
2、 項目經(jīng)理疲于應(yīng)付進(jìn)度,無心且無力;
3、 程序員水平參差不齊,缺乏正確的指導(dǎo)。
4、.經(jīng)驗不足,分析設(shè)計不到位;
5、.敏捷開發(fā),雖然經(jīng)驗很多,但為了快速開發(fā),沒有經(jīng)過分析設(shè)計;
6、.缺乏意識,只為實(shí)現(xiàn)功能而寫代碼,不管代碼質(zhì)量;
About Refacing:
重構(gòu)工作雖然重要,但是得不到過多的認(rèn)可,目前國內(nèi)關(guān)注的是可用性,對于代碼質(zhì)量并沒有得到應(yīng)有的重視。
Refacing Books:
《work effectively with legacy code》 修改代碼的藝術(shù)
《The Programtic Programmer From JoumeyMan to Master》 程序員修煉之道
《Pattern-Oriented Software Architecture Volume 4》 面向模式的軟件架構(gòu) 卷4
《Agile Principles、Patterns and Practice in C#》 敏捷軟件開發(fā) 原則、模式與實(shí)踐(C#版)
《Code Quality The Open Source Perspective》 高質(zhì)量程序設(shè)計藝術(shù)
《Refactoring improving the Designe of Existing Code》? 重構(gòu) 改善既有代碼的設(shè)計
《Design Patterns Explained 》 設(shè)計模式解析
《反模式 危機(jī)中軟件、架構(gòu)和項目的重構(gòu)》
《Refactoring to Patterns》 重構(gòu)與模式
《More Programming Pearls》 編程珠璣II
《Programming Pearls》 編程珠璣(第2版)
《Beginning Java Objects》 中文版:從概念到代碼(第2版)
《設(shè)計模式解析(第2版)》
《敏捷軟件開發(fā):原則、模式與實(shí)踐(C#版)》
《Java設(shè)計模式》
《重構(gòu)與模式》
《UML面向?qū)ο蠼Ec設(shè)計(第2版)》
轉(zhuǎn)載于:https://www.cnblogs.com/yefengmeander/archive/2011/08/18/2887695.html
總結(jié)
以上是生活随笔為你收集整理的Refactoring的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QT VS环境安装后出现生成的程序can
- 下一篇: Mysql数据库课程设计