1、爲何要代碼重構(Refactoring)程序員
在不改變系統功能的狀況下,改變系統的實現方式。爲何要這麼作?投入精力不用來知足客戶關心的需求,而是僅僅改變了軟件的實現方式,這是不是在浪費客戶的投資呢?數據庫
代碼重構的重要性要從軟件的生命週期提及。軟件不一樣與普通的產品,他是一種智力產品,沒有具體的物理形態。一個軟件不可能發生物理損耗,界面上的按鈕永遠不會由於按動次數太多而發生接觸不良。那麼爲何一個軟件製造出來之後,卻不能永遠使用下去呢?編程
對軟件的生命形成威脅的因素只有一個:需求的變動。一個軟件老是爲解決某種特定的需求而產生,時代在發展,客戶的業務也在發生變化。有的需求相對穩定一些,有的需求變化的比較劇烈,還有的需求已經消失了,或者轉化成了別的需求。在這種狀況下,軟件必須相應的改變。數組
考慮到成本和時間等因素,固然不是全部的需求變化都要在軟件系統中實現。可是總的說來,軟件要適應需求的變化,以保持本身的生命力。網絡
這就產生了一種糟糕的現象:軟件產品最初製造出來,是通過精心的設計,具備良好架構的。可是隨着時間的發展、需求的變化,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷須要修改。爲了實現變動,不可避免的要違反最初的設計構架。通過一段時間之後,軟件的架構就千瘡百孔了。bug愈來愈多,愈來愈難維護,新的需求愈來愈難實現,軟件的構架對新的需求漸漸的失去支持能力,而是成爲一種制約。最後新需求的開發成本會超過開發一個新的軟件的成本,這就是這個軟件系統的生命走到盡頭的時候。架構
代碼重構就可以最大限度的避免這樣一種現象。系統發展到必定階段後,使用重構的方式,不改變系統的外部功能,只對內部的結構進行從新的整理。經過重構,不斷的調整系統的結構,使系統對於需求的變動始終具備較強的適應能力。佈局
2、經過代碼重構能夠達到如下的目標編碼
持續偏糾和改進軟件設計設計
重構和設計是相輔相成的,它和設計彼此互補。有了重構,你仍然必須作預先的設計,可是沒必要是最優的設計,只須要一個合理的解決方案就夠了,若是沒有重構、程序設計會逐漸腐敗變質,越來越像斷線的風箏,脫繮的野馬沒法控制。重構其實就是整理代碼,讓全部帶着發散傾向的代碼迴歸本位。代理
使代碼更易爲人所理解
Martin Flower在《重構》中有一句經典的話:"任何一個傻瓜都能寫出計算機能夠理解的程序,只有寫出人類容易理解的程序纔是優秀的程序員。"對此,筆者感觸很深,有些程序員老是可以快速編寫出可運行的代碼,但代碼中晦澀的命名令人暈眩得須要緊握坐椅扶手,試想一個新兵到來接手這樣的代碼他會不會想當逃兵呢?
軟件的生命週期每每須要多批程序員來維護,咱們每每忽略了這些後來人。爲了使代碼容易被他人理解,須要在實現軟件功能時作許多額外的事件,如清晰的排版佈局,簡明扼要的註釋,其中命名也是一個重要的方面。一個很好的辦法就是採用暗喻命名,即以對象實現的功能的依據,用形象化或擬人化的手法進行命名,一個很好的態度就是將每一個代碼元素像新生兒同樣命名,也許筆者有點命名偏執狂的傾向,如能榮此雅號,將深以此爲幸。
對於那些讓人充滿迷茫感甚至誤導性的命名,須要果決地、大刀闊斧地整容,永遠不要手下留情!
幫助發現隱藏的代碼缺陷
重構代碼時逼迫你加深理解原先所寫的代碼。筆者常有寫下程序後,卻發生對本身的程序邏輯不甚理解的情景,曾爲此驚悚過,後來發現這種症狀竟然是許多程序員常患的"感冒"。當你也發生這樣的情形時,經過重構代碼能夠加深對原設計的理解,發現其中的問題和隱患,構建出更好的代碼。
從長遠來看,有助於提升編程效率
當你發現解決一個問題變得異常複雜時,每每不是問題自己形成的,而是你用錯了方法,拙劣的設計每每致使臃腫的編碼。
改善設計、提升可讀性、減小缺陷都是爲了穩住陣腳。良好的設計是成功的一半,停下來經過重構改進設計,或許會在當前減緩速度,但它帶來的後發優點倒是不可低估的。
3、哪些狀況須要考慮代碼重構
臃腫的類: 類之因此會臃腫,是由於開發者缺少對最基本的編碼原則,即「單一職責原則」(SRP)的理解。這些類每每會變得很臃腫,是因爲不一樣的且在功能上缺乏關聯的方法都放在了相同的類裏面。
長方法: 方法之因此會變得很長主要是有如下幾個緣由:
一、許多沒有關聯性的、功能複雜的模塊的代碼都放在相同的方法內。這主要是開發者缺少SRP的概念。
二、多種條件都放在同一個方法內,這在長方法內常常會發生的。這是因爲缺少McCabe代碼複雜度和SRP的概念的比較。
大量的傳參: 我常常遇到這幾種狀況,一些方法跟另外一些方法進行交互,或者調用另外一些方法的時候傳入大量的參數。這就會出現若是更改了其中一個參數,就得在多個方法內進行更改。
常量值無處不在: 常常會發現開發者(尤爲是新手)會使用一些具備明確含義的常量值(主要是魔鬼數字),但沒有給它們賦予合適的常量變量。這會下降代碼的可讀性和可理解性。
模糊的方法名: 許多時候,如下取的方法名會影響代碼的可讀性和可理解性:
一、模糊的不具備任何意義的方法名
二、技術性的,卻沒有說起相關領域的名稱
4、重構的方法
提取類/抽離方法
正如上面提到的,像「臃腫的類」(一個類提供了本該有幾個類提供的功能)這種代碼異味應該將原有類中的方法和屬性移動到適當數目的新類中去。舊類中對應新類的方法和屬性應該被移除。另外,有時候一些類過於臃腫是由於它包含了被其餘類使用本應該是其餘類的成員方法的成員方法。這些方法也應該被遷移到合適的類中。
提取方法
像上面提到的「過長的方法」這種代碼異味能夠經過從舊方法中提取代碼到一個或多個新方法中消除。
分離條件
許多時候,一個方法很長是由於包含好幾個分支語句(if-else)。這些分支條件能夠被提取和移動到幾個單獨的方法中。這確實能大大改善代碼可讀性和可理解性。
引入參數對象/保留全局對象
在我作代碼審查時發現另一個很常見的狀況 - 好幾個參數被傳入方法。問題主要與須要從已有方法中增長或者移除一個方法參數有關。在這種場景,建議將相關方法參數組成一個對象(引入參數對象),讓方法傳遞這些對象而不是每一個單獨的參數。
用符號常量替換魔法數字
對於有意義的而且處處被使用的字面常量,應該爲它們分配一個命名常量。這能大大加強代碼可讀性和可理解性。
重命名方法
正如上面提到的,模糊不清的方法名會影響代碼的可以使用性。這些模糊不清的名稱應該重命名爲有意義的可能與業務術語有關的名稱,來幫助開發者經過業務上下文更好地理解代碼。這很須要技巧而且要求開發者與業務專家一塊兒協做來理清代碼須要知足的業務需求。有趣的是,這種重構方法看起來彷佛很是容易理解,可是經常被許多開發者忽視,雖然在Eclipse這種IDE的refactor菜單項中常常出現這一項。
5、當重構沒有現成的明顯的方向時,咱們能夠遵循下面的原則
一、當屬性、方法或類存在任何的須要複用的意向時,概括提煉它們。
二、不要低估小方法對代碼整潔的做用。使用小方法能讓你節省不少筆墨。
三、用封裝控制可見度。
四、消除依賴。
五、簡化構造方法——即便這樣作會使代碼變複雜。
六、不肯定時,將計算操做移入到這些數據的全部者對象裏,或將數據移動到執行計算操做的對象裏(也就是迪米特法則(Law of Demeter))。
七、使用小對象,鬆耦合,避免大對象,高聚合。
八、使用代理對象,模擬對象和輔助對象來隔離網絡,數據庫,文件和用戶接口。
九、不肯定時,儘可能在model裏添加代碼,必要時才往controler添加代碼。view裏添加的都應該是便捷功能和簡寫方法,但不要侷限於此。