代碼重構(gòu)

一、為什么要代碼重構(gòu)(Refactoring)

在不改變系統(tǒng)功能的情況下,改變系統(tǒng)的實(shí)現(xiàn)方式。為什么要這么做?投入精力不用來(lái)滿(mǎn)足客戶(hù)關(guān)心的需求,而是僅僅改變了軟件的實(shí)現(xiàn)方式,這是否是在浪費(fèi)客戶(hù)的投資呢?

代碼重構(gòu)的重要性要從軟件的生命周期說(shuō)起。軟件不同與普通的產(chǎn)品,他是一種智力產(chǎn)品,沒(méi)有具體的物理形態(tài)。一個(gè)軟件不可能發(fā)生物理?yè)p耗,界面上的按鈕永遠(yuǎn)不會(huì)因?yàn)榘磩?dòng)次數(shù)太多而發(fā)生接觸不良。那么為什么一個(gè)軟件制造出來(lái)以后,卻不能永遠(yuǎn)使用下去呢?

對(duì)軟件的生命造成威脅的因素只有一個(gè):需求的變更。一個(gè)軟件總是為解決某種特定的需求而產(chǎn)生,時(shí)代在發(fā)展,客戶(hù)的業(yè)務(wù)也在發(fā)生變化。有的需求相對(duì)穩(wěn)定一些,有的需求變化的比較劇烈,還有的需求已經(jīng)消失了,或者轉(zhuǎn)化成了別的需求。在這種情況下,軟件必須相應(yīng)的改變。

考慮到成本和時(shí)間等因素,當(dāng)然不是所有的需求變化都要在軟件系統(tǒng)中實(shí)現(xiàn)。但是總的說(shuō)來(lái),軟件要適應(yīng)需求的變化,以保持自己的生命力。

這就產(chǎn)生了一種糟糕的現(xiàn)象:軟件產(chǎn)品最初制造出來(lái),是經(jīng)過(guò)精心的設(shè)計(jì),具有良好架構(gòu)的。但是隨著時(shí)間的發(fā)展、需求的變化,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷需要修改。為了實(shí)現(xiàn)變更,不可避免的要違反最初的設(shè)計(jì)構(gòu)架。經(jīng)過(guò)一段時(shí)間以后,軟件的架構(gòu)就千瘡百孔了。bug越來(lái)越多,越來(lái)越難維護(hù),新的需求越來(lái)越難實(shí)現(xiàn),軟件的構(gòu)架對(duì)新的需求漸漸的失去支持能力,而是成為一種制約。最后新需求的開(kāi)發(fā)成本會(huì)超過(guò)開(kāi)發(fā)一個(gè)新的軟件的成本,這就是這個(gè)軟件系統(tǒng)的生命走到盡頭的時(shí)候。

代碼重構(gòu)就能夠最大限度的避免這樣一種現(xiàn)象。系統(tǒng)發(fā)展到一定階段后,使用重構(gòu)的方式,不改變系統(tǒng)的外部功能,只對(duì)內(nèi)部的結(jié)構(gòu)進(jìn)行重新的整理。通過(guò)重構(gòu),不斷的調(diào)整系統(tǒng)的結(jié)構(gòu),使系統(tǒng)對(duì)于需求的變更始終具有較強(qiáng)的適應(yīng)能力。

二、通過(guò)代碼重構(gòu)可以達(dá)到以下的目標(biāo)
2.1 持續(xù)偏糾和改進(jìn)軟件設(shè)計(jì)

重構(gòu)和設(shè)計(jì)是相輔相成的,它和設(shè)計(jì)彼此互補(bǔ)。有了重構(gòu),你仍然必須做預(yù)先的設(shè)計(jì),但是不必是最優(yōu)的設(shè)計(jì),只需要一個(gè)合理的解決方案就夠了,如果沒(méi)有重構(gòu)、程序設(shè)計(jì)會(huì)逐漸腐敗變質(zhì),愈來(lái)愈像斷線(xiàn)的風(fēng)箏,脫韁的野馬無(wú)法控制。重構(gòu)其實(shí)就是整理代碼,讓所有帶著發(fā)散傾向的代碼回歸本位。

2.2 使代碼更易為人所理解

軟件的生命周期往往需要多批程序員來(lái)維護(hù),我們往往忽略了這些后來(lái)人。為了使代碼容易被他人理解,需要在實(shí)現(xiàn)軟件功能時(shí)做許多額外的事件,如清晰的排版布局,簡(jiǎn)明扼要的注釋?zhuān)渲忻彩且粋€(gè)重要的方面。一個(gè)很好的辦法就是采用暗喻命名,即以對(duì)象實(shí)現(xiàn)的功能的依據(jù),用形象化或擬人化的手法進(jìn)行命名,一個(gè)很好的態(tài)度就是將每個(gè)代碼元素像新生兒一樣命名,也許筆者有點(diǎn)命名偏執(zhí)狂的傾向,如能榮此雅號(hào),將深以此為幸。

對(duì)于那些讓人充滿(mǎn)迷茫感甚至誤導(dǎo)性的命名,需要果決地、大刀闊斧地整容,永遠(yuǎn)不要手下留情!

2.3 幫助發(fā)現(xiàn)隱藏的代碼缺陷

重構(gòu)代碼時(shí)逼迫你加深理解原先所寫(xiě)的代碼。筆者常有寫(xiě)下程序后,卻發(fā)生對(duì)自己的程序邏輯不甚理解的情景,曾為此驚悚過(guò),后來(lái)發(fā)現(xiàn)這種癥狀居然是許多程序員常患的"感冒"。當(dāng)你也發(fā)生這樣的情形時(shí),通過(guò)重構(gòu)代碼可以加深對(duì)原設(shè)計(jì)的理解,發(fā)現(xiàn)其中的問(wèn)題和隱患,構(gòu)建出更好的代碼。

2.4 從長(zhǎng)遠(yuǎn)來(lái)看,有助于提高編程效率

當(dāng)你發(fā)現(xiàn)解決一個(gè)問(wèn)題變得異常復(fù)雜時(shí),往往不是問(wèn)題本身造成的,而是你用錯(cuò)了方法,拙劣的設(shè)計(jì)往往導(dǎo)致臃腫的編碼。

改善設(shè)計(jì)、提高可讀性、減少缺陷都是為了穩(wěn)住陣腳。良好的設(shè)計(jì)是成功的一半,停下來(lái)通過(guò)重構(gòu)改進(jìn)設(shè)計(jì),或許會(huì)在當(dāng)前減緩速度,但它帶來(lái)的后發(fā)優(yōu)勢(shì)卻是不可低估的。

三、哪些情況需要考慮代碼重構(gòu)

3.1 臃腫的類(lèi)

類(lèi)之所以會(huì)臃腫,是因?yàn)殚_(kāi)發(fā)者缺乏對(duì)最基本的編碼原則,即“單一職責(zé)原則”(SRP)的理解。這些類(lèi)往往會(huì)變得很臃腫,是由于不同的且在功能上缺少關(guān)聯(lián)的方法都放在了相同的類(lèi)里面。

3.2 長(zhǎng)方法

方法之所以會(huì)變得很長(zhǎng)主要是有以下幾個(gè)原因:

  • 1: 許多沒(méi)有關(guān)聯(lián)性的、功能復(fù)雜的模塊的代碼都放在相同的方法內(nèi)。這主要是開(kāi)發(fā)者缺乏SRP的概念
  • 2: 多種條件都放在同一個(gè)方法內(nèi),這在長(zhǎng)方法內(nèi)經(jīng)常會(huì)發(fā)生的。這是由于缺乏McCabe代碼復(fù)雜度和SRP的概念的比較。
3.3 大量的傳參

我經(jīng)常遇到這幾種情況,一些方法跟另一些方法進(jìn)行交互,或者調(diào)用另一些方法的時(shí)候傳入大量的參數(shù)。這就會(huì)出現(xiàn)如果更改了其中一個(gè)參數(shù),就得在多個(gè)方法內(nèi)進(jìn)行更改。

3.4 常量值無(wú)處不在

經(jīng)常會(huì)發(fā)現(xiàn)開(kāi)發(fā)者(尤其是新手)會(huì)使用一些具有明確含義的常量值(主要是魔鬼數(shù)字),但沒(méi)有給它們賦予合適的常量變量。這會(huì)降低代碼的可讀性和可理解性。

3.5 模糊的方法名

許多時(shí)候,以下取的方法名會(huì)影響代碼的可讀性和可理解性:

  • 1: 模糊的不具有任何意義的方法名
  • 2: 技術(shù)性的,卻沒(méi)有提及相關(guān)領(lǐng)域的名稱(chēng)

四、重構(gòu)的方法

4.1 提取類(lèi)/抽離方法

正如上面提到的,像“臃腫的類(lèi)”(一個(gè)類(lèi)提供了本該有幾個(gè)類(lèi)提供的功能)這種代碼異味應(yīng)該將原有類(lèi)中的方法和屬性移動(dòng)到適當(dāng)數(shù)目的新類(lèi)中去。舊類(lèi)中對(duì)應(yīng)新類(lèi)的方法和屬性應(yīng)該被移除。另外,有時(shí)候一些類(lèi)過(guò)于臃腫是因?yàn)樗吮黄渌?lèi)使用本應(yīng)該是其他類(lèi)的成員方法的成員方法。這些方法也應(yīng)該被遷移到合適的類(lèi)中。

4.2 提取方法

像上面提到的“過(guò)長(zhǎng)的方法”這種代碼異味可以通過(guò)從舊方法中提取代碼到一個(gè)或多個(gè)新方法中消除。

4.3 分離條件

許多時(shí)候,一個(gè)方法很長(zhǎng)是因?yàn)榘脦讉€(gè)分支語(yǔ)句(if-else)。這些分支條件可以被提取和移動(dòng)到幾個(gè)單獨(dú)的方法中。這確實(shí)能大大改善代碼可讀性和可理解性。

4.4 引入?yún)?shù)對(duì)象/保留全局對(duì)象

在我做代碼審查時(shí)發(fā)現(xiàn)另外一個(gè)很常見(jiàn)的情況 - 好幾個(gè)參數(shù)被傳入方法。問(wèn)題主要與需要從已有方法中增加或者移除一個(gè)方法參數(shù)有關(guān)。在這種場(chǎng)景,建議將相關(guān)方法參數(shù)組成一個(gè)對(duì)象(引入?yún)?shù)對(duì)象),讓方法傳遞這些對(duì)象而不是每個(gè)單獨(dú)的參數(shù)。

4.5 用符號(hào)常量替換魔法數(shù)字

對(duì)于有意義的并且到處被使用的字面常量,應(yīng)該為它們分配一個(gè)命名常量。這能大大增強(qiáng)代碼可讀性和可理解性。

4.6 重命名方法

正如上面提到的,模糊不清的方法名會(huì)影響代碼的可使用性。這些模糊不清的名稱(chēng)應(yīng)該重命名為有意義的可能與業(yè)務(wù)術(shù)語(yǔ)有關(guān)的名稱(chēng),來(lái)幫助開(kāi)發(fā)者通過(guò)業(yè)務(wù)上下文更好地理解代碼。這很需要技巧并且要求開(kāi)發(fā)者與業(yè)務(wù)專(zhuān)家一起協(xié)作來(lái)理清代碼需要滿(mǎn)足的業(yè)務(wù)需求。有趣的是,這種重構(gòu)方法看起來(lái)似乎非常容易理解,但是常常被許多開(kāi)發(fā)者忽視,雖然在Eclipse這種IDE的refactor菜單項(xiàng)中經(jīng)常出現(xiàn)這一項(xiàng)。

五、當(dāng)重構(gòu)沒(méi)有現(xiàn)成的明顯的方向時(shí),我們可以遵循下面的原則

1、當(dāng)屬性、方法或類(lèi)存在任何的需要復(fù)用的意向時(shí),歸納提煉它們。

2、不要低估小方法對(duì)代碼整潔的作用。使用小方法能讓你節(jié)省很多筆墨。

3、用封裝控制可見(jiàn)度。

4、消除依賴(lài)。

5、簡(jiǎn)化構(gòu)造方法——即使這樣做會(huì)使代碼變復(fù)雜。

6、不確定時(shí),將計(jì)算操作移入到這些數(shù)據(jù)的所有者對(duì)象里,或?qū)?shù)據(jù)移動(dòng)到執(zhí)行計(jì)算操作的對(duì)象里(也就是迪米特法則(Law of Demeter))。

7、使用小對(duì)象,松耦合,避免大對(duì)象,高聚合。

8、使用代理對(duì)象,模擬對(duì)象和輔助對(duì)象來(lái)隔離網(wǎng)絡(luò),數(shù)據(jù)庫(kù),文件和用戶(hù)接口。

9、不確定時(shí),盡量在model里添加代碼,必要時(shí)才往controler添加代碼。view里添加的都應(yīng)該是便捷功能和簡(jiǎn)寫(xiě)方法,但不要局限于此。

代碼重構(gòu)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 代碼重構(gòu)簡(jiǎn)介:(英語(yǔ):Code refactoring)重構(gòu)就是在不改變軟件系統(tǒng)外部行為的前提下,改善它的內(nèi)部結(jié)構(gòu)...
    TaiXiang閱讀 3,056評(píng)論 0 2
  • 閱讀《重構(gòu)》的筆記獻(xiàn)上。 重構(gòu)的定義 重構(gòu)是在不改變軟件可觀察行為的前提下改善其內(nèi)部結(jié)構(gòu)。 重構(gòu)的節(jié)奏 以微小的步...
    陳宇明閱讀 11,751評(píng)論 13 64
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,745評(píng)論 25 709
  • 寫(xiě)在文前:大部分程序員都能寫(xiě)出計(jì)算機(jī)可以理解的代碼,唯有優(yōu)秀的程序員才能寫(xiě)出讓人容易理解的代碼 最近幾個(gè)月被分配了...
    niknowzcd閱讀 2,048評(píng)論 8 5
  • 夜未安閱讀 282評(píng)論 0 1

友情鏈接更多精彩內(nèi)容