開天眼,頓悟軟件設計之道

本文摘自http://tech.it168.com/j/n/2007-07-10/200707101017099_3.shtml

開天眼,頓悟軟件設計之道

 

<script type="text/javascript"></script>



    【IT168 專稿】夜深人靜,四周一片寧靜,月光如水銀般傾泄,把大地染成一片銀白。此時,滿天的繁星像無數顆璀璨的寶石,把浩翰的夜空點綴得點點閃爍。與此相影成趣的是億景公司三樓軟開發部卻燈火通明。蒼穹無言,星月含情。也不知道過了多久,東方的天空開始漸漸發白,不知不覺中已近天明。張力揉搓了一下通紅的雙眼,然後繼續加班修改昨天給項目主管退回來的軟件程序。張力是一個軟件開發程序員,在昨天的軟件項目開發評審會議上,他負責的程序被項目經理西門評點爲完全不符合OO設計模式和設計之道。軟件設計嚴重出現四個“腐爛”的徵兆,就是過於僵硬、過於脆弱、不可複用性和粘滯性過高。

張力看着窗外發白的天空,想起了項目經理西門對他的評價:一是程序過於僵硬,使軟件難以更改,每一個改動都會造成一連串互相依靠的模塊的改動,這樣的後果是誰也不敢改動,因爲他永遠也不知道一個改動何時才能完成。二是過於脆弱,會使當軟件改動時,系統會在許多地方出錯,並且錯誤經常發生在概念上與改動的地方沒有直接聯繫的模塊中。這樣的軟件無法維護,而且每一次維護都使軟件變得更加難以維護。還有就是不可複用性,致使不能複用在其它項目中、或本項目的其它位置中。張力嘆了一口氣,難道他的軟件設計真的象西門經理下班前說的一句話,他還沒有開天眼,領悟軟件設計之道?

    一.什麼是軟件設計之道?

    終於捱到了上班的時候,張力趕快洗個臉後走到項目主管西門經理的辦公室,向他請教什麼是開天眼和悟道。西門看着一整夜沒有睡覺而雙眼通紅的張力說:“什麼是道?道是人們對於世界的一些最基本的規律和法則的認識。悟道有五眼六通之說,其中以天眼通爲首。大家或多或少都聽說過“道”這個詞,卻不知關鍵中的關鍵是什麼?簡單說就是越是簡單的道理越是接近本質。悟者,是能將眼前反觀內境,能將身側遠望星空。悟性高的人,是站得更高,看得更遠,想得更深,做得更接近本質。悟心就是覺悟之心,我們把透徹一種智慧稱爲“悟道”。而穿透和超越了事物表象,直接達到事物的本來面目的智慧,可以稱作 “頓悟”——就是在剎那間豁然貫通、洞若觀火。

    “軟件設計也需要用心體會方能悟出軟件設計之“道”。軟件設計之“道”,也不在於設計有多麼的華麗、精巧,而在於其樸實、自然,最終達到“以無招勝有招”,進入一個新的境界”。西門停頓了一下,繼續說:“那麼,在軟件設計過程中是否存在一些基本的原則,我們可以在今天的軟件交流會上與各同事再探討一些在軟件設計中最基本的原則”。

    “程序設計的上乘修練方法,可分成兩個部份,就是外家功夫和內家功夫。上乘的軟件設計之道必須剛柔相濟、內外兼修,迴歸自然,遵守基本法則”。西門在軟件設計交流會上總結說:“要想悟出軟件設計之道,我們先看看系統的一些“外家”特性,包括可讀性、高靈活性、易擴展性、通用性、可移植性,這些特性可概括爲“外家白箱特性”。而系統內部也要有一些“內家”屬性,如高內聚、低耦合,這些內部屬性更側重內部結構性,概括爲“內家黑箱屬性”。

    同時,西門還提到爲了使一個系統設計具有這些優秀的特性,可使用一些手段和方法。這些方法/手段包括抽象(提高通用性)、封裝(增強內聚性)、分離(降低耦合性)等等。當對這些方法/手段進行細化、分類、概括時,就產生了一些設計原則/準則,比如面向接口編程、優先使用對象組合等等。這些準則/原則在一定場景下的經典表現方式,就產生了設計模式。
二.外家白箱之道:可讀性與複用性
    軟件設計的“外家”白箱之道,包括可讀性、高靈活性、易擴展性、通用性、可移植等。這裏主要詳細介紹兩點:一是可讀性,二是複用性。

    一個軟件的生命週期中,80%的時間和成本花費在維護上。我們可以看到幾乎沒有任何一個軟件,在其整個生命週期中,均由最初的開發人員來維護。無論是從軟件的修改,測試還是移植的角度來看,軟件的可讀性都需要提到一個非常重要的位置上。常用改善軟件的可讀性方法有編碼規範,而不僅僅是詳細的註釋說明。可讀性強的編碼規範對於程序員尤爲重要,可以讓程序員儘快而徹底地理解新的代碼。另一個方面,可讀性強的設計對測試檢查Bug也是非常重要。因此建議在軟件設計中必須執行規範,每個軟件開發人員必須一致遵守編碼規範,提高程序的可讀性。

    爲了應對軟件危機的需要,軟件設計原則的最高層次是:複用性、擴展性。很多的軟件方案中,開宗明義自己的設計原則是面向對象。那麼,當我們把需求影射成爲一個一個的對象,就是好的設計嗎?事實上,如何劃分、設計真正好的對象,是非常難以掌握的。實際上,我們都知道面向對象的基本初衷是代碼複用。可複用性是通過複用之前的勞動成果提高開發效率,降低成本。圍繞可複用性有很多東西和層次,如代碼級別的複用,設計的複用,組件的複用,還有框架的複用等。

    軟件的複用除了可以提高軟件的生產率,並且恰當的複用可以提高軟件的可維護性。在以前,複用主要是代碼,函數,結構的複用。而現在複用主要針對類,接口,組件等。但是複用並不一定會保證軟件的可維護性。不能因爲代碼的重複等原因就複用,需要根據具體的情況來分析。要想通過複用來加強系統的可維護性,必須保證複用是支持可維護性的複用。

    下面的一些最基本的確設計原則可以用來指導實踐。
    開-閉原則(OCP):開閉原則是面向對象可複用的基石。它主要指:一個軟件實體對擴展開放,對修改關閉。在設計一個模塊的時候,應當是這個模塊在不被修改的前提下被擴展。滿足這個原則的系統在一個較高層次上實現了複用,也是易於維護的。
    那如何才能滿足開閉原則呢?抽象化是關鍵,要區分開抽象層和實現層。在一個軟件系統中,抽象層應該是相對穩定的,而實現層是可以改變和擴展的。我們可以把許多事物和問題抽象起來,並且抽象它們不同的層次和角度。開閉原則也是對可變性的封裝原則,找到系統的可變因素,並將其封裝起來。把一種可變性封裝爲一個對象,那麼這種可變性的不同表象就是這個類的具體子類。

    里氏代換原則(LSP):里氏代換原則是繼承複用的基石:在任何父類出現的地方都可以用它的子類來替代。實際上,設計類的階層體系結構時,這是一條很重要的原則。另一個需要着重提到的是依賴倒轉原則(DIP):就是說要依賴於抽象,不要依賴於具體的實現。在傳統的過程性系統中,高層的模塊依賴於低層次的模塊,抽象層次依賴於具體層次。這樣導致了底層的任何改變都會影響到上層。這樣的軟件系統沒有可維護性而言。抽象層次應該不依賴於具體的實現細節,這樣才能保證系統的可複用性和可維護性,這也就是所謂的倒轉。

     在實際中如何應用這一原則呢?要針對接口編程,而不針對實現編程。那麼當實現變化時,不會影響到其他的地方。在java中應當使用接口和抽象類來進行變量的類型聲明,參數的類型聲明,方法的返回值類型等等。以抽象的方式進行耦合是依賴倒轉原則的關鍵。依照依賴倒轉原則,在系統中會出現大量的類,如抽象類和接口,因爲它假定所有的具類都是有可能變化的。
三.內家黑箱之道:低耦合、高聚合

    如果將設計好的對象之間用有向箭頭連在一起,很多時候會變成了一張網,如果將對象的方法之間用有向箭頭連在一起,則看起來像信手塗鴉。對於設計人員,能夠將其中的關係一一說明清楚也是一個困難的事情,而對於的開發人員,則變成了黑洞。當用戶需求發生變化時,這樣的設計會成爲噩夢,當然這是比較極端的情況。但是也能說明,在設計各個層面減少耦合是關鍵。

    一般來說,大部份的軟件內部都是包含多個模塊的,各個模塊之間或多或少的存在一些耦合。這些功能的耦合,最理想的一種狀態,就是可配置,可裝卸。任何一個模塊的去除,不至於影響到其他功能。並且,更多的功能是採用配置的。就是說,各個模塊,就像搭積木一樣,可以把其中的一塊替換掉,或者拿掉,但不可以影響其他的功能。可配置,可裝卸的軟件,必將是未來軟件更爲理想的開發模式。這對於系統的維護,以及需求的變更適應性都是非常好的。

    因此“內家黑箱”設計之道是:低耦合、高聚合。各種軟件設計的原則,如依賴倒置原則、單一職則原則、面向接口等,以及各種設計模式,其根本的目的其實只是爲了降低耦合。因爲只有低耦合才能更好的適應變化,更好的複用和擴展。

    一般來說,我們常用的實現方法是:運用設計模式封裝變化、降低耦合。設計模式是用來“封裝變化、降低耦合”的工具。它是面向對象設計的產物,其本質就是充分運用面向對象的三個特性,即:封裝、繼承和多態,進行靈活的組合運用。

    當然,耦合無論如何也是不可避免的。當我們實現接口、繼承父類的時候,就會不可避免的產生耦合。但耦合是有不同粒度的,我們必須非常清楚的是解耦需要到什麼粒度爲止。一般來說應以模塊的複用粒度爲準,儘量解除複用模塊或對象之間的耦合。而複用模塊之內的耦合,應屬於聚合的範疇,所以不要盲目的去解耦,否則就陷入了誤區。

    在這裏,我們再回達頭來看看怎樣才能解耦。一般有以下兩個思路:(1)將具體的東西抽象處理。(2)將分散的東西集中處理。降低耦合,也就是解耦是關鍵。當我們實現了低耦合,高內聚,也同時達到了軟件設計的另一個目標高擴展,高複用。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章