標籤:des style blog http color 使用
軟體,自從被我們開發出來並交付使用以後,如果它運行得好好的,我們是不會去修改它的。我們要修改軟體,萬變不離其宗,無非就是四種動機:
1.增加新功能;
2.原有功能有BUG;
3.改善原有程式的結構;
4.最佳化原有系統的效能[1]。
第一種和第二種動機,都是源於客戶的功能需求,而第四種是源於客戶的非功能需求。
軟體的外部品質,其衡量的標準就是客戶對軟體功能需求與非功能需求的滿意度。它涉及到一個企業、一個軟體的信譽度與生命力,因此為所有軟體企業所高度重視。但是,就在所有企業高管把軟體外部品質放在高於一切的高度的同時,軟體內部品質卻長期為人所漠視。企業沒有保證軟體內部品質的措施,甚至因為需要趕工而肆意地降低內部品質的標準。這樣帶來的長期惡果就是,程式編寫越來越爛,運行效率越來越低,程式結構越來越讓人看不懂。當一群群剛剛畢業的大學生遊走在這堆寫得很爛的代碼中時,他們開始沉淪,開始天真地以為代碼就是這樣寫的(真是毀人不倦呀)。當我們的軟體企業培養出一批批品質不高的開發人員,開發出一個個品質低下的軟體系統時,它們開始發現軟體維護成本越來越高,最終不得不收穫自己種下的惡果。
要提高軟體內部品質,毫無疑問就是軟體修改的第三個動機:改善原有程式的結構。它的價值是隱性的,並不體現在某一次或兩次開發中,而是逐漸體現在日後長期維護的軟體過程中。高品質的軟體,可以保證開發人員(即使是新手)能夠輕易看懂軟體代碼,能夠保證日後的每一次軟體維護都可以輕易地完成(不論軟體經曆了多少次變更,維護了多少年),能夠保證日後的每一次需求變更都能夠輕易地進行(而不是傷筋動骨地大動)。要做到這幾點其實並不容易,它需要我們持續不斷地對系統內部品質進行最佳化與改進。這,就是系統重構的價值。
為了有效提高軟體的內部品質,我們在系統重構中應當做哪些事情呢?首先是提高軟體的可讀性、易於閱讀。軟體要可讀,並不是添加幾行注釋那麼簡單的事兒,首先是軟體的商務邏輯要清晰。一個商務程序可能其處理過程可能非常複雜,如果在一個函數中順序地一行一行寫下來,可能需要寫數百行,甚至上千行。比如,我們要實現這樣一個需求:像Spring那樣從一個或者數個設定檔中讀取XML,然後根據XML依次去建立每一個bean,將每一個bean放到beanFactory中。如果沒有經過精心地設計,而是隨性地一行一行寫,要實現這個功能沒個幾百上千行代碼,想想都難。但如果我們換個思路,在入口函數裡僅僅調用幾個頂級方法,比如findXmlFile()、readXmlStream()、buildFactory(),然後依次去實現這幾個頂級方法,程式結構就會變得清晰而易讀。請看這段範例程式碼:
1 public abstract class XmlBuildFactoryTemplate { 2 /** 3 * 初始化工廠。根據路徑讀取XML檔案,將XML檔案中的資料裝載到工廠中 4 * @param path XML檔案的路徑 5 */ 6 public void initFactory(String path){ 7 //尋找XML檔案,讀取資料流 8 InputStream inputStream = findXmlFile(path); 9 //解析XML檔案,返回根10 Element root = readXmlStream(inputStream);11 //根據XML檔案建立類,放入工廠中12 buildFactory(root);13 }14 /**15 * 讀取一個XML的檔案,輸出其資料流16 * @param path XML檔案的路徑17 * @return InputStream檔案輸入資料流18 */19 protected InputStream findXmlFile(Stringpath) {20 ......21 }22 /**23 * 讀取並解析一個XML的檔案輸入資料流,以Element的形式擷取XML的根,返回之24 * @param inputStream 檔案輸入資料流25 * @return ElementXML的根26 */27 protected Element readXmlStream (InputStream inputStream) {28 ......29 }30 /**31 * 用從一個XML的檔案中讀取的資料構建工廠32 * @param root 從一個XML的檔案中讀取的資料的根33 */34 protected abstract void buildFactory(Element root);35 }
在實現這幾個頂級函數的時候,我們還會將一些比較獨立的功能分解出去,形成類與介面,比如這裡的findXmlFile(),它可能會以各種方式去尋找XML檔案,這時把這些功能提取出來,形成Resource介面和它的多個實現(1.1所示),為findXmlFile()所調用。如果我們將這個複雜的功能設計成這樣,則毫無疑問,系統可讀性將大大提高。
圖1.1 工廠類模板的設計圖
此外,在物件導向的世界裡,我們設計的類、方法、關聯,應當與現實世界中的事物、行為,及其相互的關係對應起來。現實世界有什麼事物,這些事物都應當有什麼行為,相互之間是什麼關係,則我們在軟體世界裡就應當設計什麼類、什麼方法和它們之間的關聯關係。只有這樣的設計才是最易於為人所理解的設計,這就是“領域驅動設計”的思想[1]。在系統重構中,我們將使用“抽取方法”來分解難於閱讀與維護的大函數,用“抽取對象”來分解無所不能的大對象。
系統重構要乾的另一件事情就是使軟體易於維護、易於變更。軟體需求總是變得越來越複雜,這是無法改變的客觀事實。在添加新功能的同時,我們既要保證原有代碼的有效性,又必須有效地複用原有的代碼。這是多麼矛盾的一件事兒啊!怎麼辦呢?看我在後面一步一步給你分解……
[1] 領域驅動設計(DDD: Domain-DrivenDesign),源自軟體理論大師Eric Evans在其2010年發表的同名著作中提出來的設計思想,本文將大量提及。
大話重構連載首頁:http://www.cnblogs.com/mooodo/p/talkAboutRefactoringHome.html
特別說明:希望網友們在轉載本文時,應當註明作者或出處,以示對作者的尊重,謝謝!