我偶然在google或yahoo這樣的搜索引擎搜索GRASP發現,除了國外的網站,國內網站多介紹和討論GoF而很少介紹GRASP,即使這少量的文章也講解非常粗略。個人認為作為優秀的開發人員,理解GRASP比GoF更重要,故寫此文章。前面我在 《 ( 原創)一個優秀軟件開發人員的必修課: GRASP 軟件開發模式淺析 》 中介紹了使用GRASP的目的,今天允許我調換一下順序,先從低耦合講起,因為諸如創建者模式、信息專家模式的根本目的就是降低耦合。
1. 低耦合( Low Coupling )
“低耦合”這個詞相信大家已經耳熟能詳,我們在看 spring 的書籍、 MVC 的數據、設計模式的書籍,無處不提到“低耦合、高內聚”,它已經成為軟件設計質量的標準之一。那么什么是低耦合?耦合就是對某元素與其它元素之間的連接、感知和依賴的量度。這里所說的元素,即可以是功能、對象(類),也可以指系統、子系統、模塊。假如一個元素 A 去連接元素 B ,或者通過自己的方法可以感知 B ,或者當 B 不存在的時候就不能正常工作,那么就說元素 A 與元素 B 耦合。耦合帶來的問題是,當元素 B 發生變更或不存在時,都將影響元素 A 的正常工作,影響系統的可維護性和易變更性。同時元素 A 只能工作于元素 B 存在的環境中,這也降低了元素 A 的可復用性。正因為耦合的種種弊端,我們在軟件設計的時候努力追求“低耦合”。低耦合就是要求在我們的軟件系統中,某元素不要過度依賴于其它元素。請注意這里的“過度”二字。系統中低耦合不能過度,比如說我們設計一個類可以不與 JDK 耦合,這可能嗎?除非你不是設計的 Java 程序。再比如我設計了一個類,它不與我的系統中的任何類發生耦合。如果有這樣一個類,那么它必然是低內聚(關于內聚的問題我隨后討論)。耦合與內聚常常是一個矛盾的兩個方面。最佳的方案就是尋找一個合適的中間點。
哪些是耦合呢?
1 .元素 B 是元素 A 的屬性,或者元素 A 引用了元素 B 的實例(這包括元素 A 調用的某個方法,其參數中包含元素 B )。
2 .元素 A 調用了元素 B 的方法。
3 .元素 A 直接或間接成為元素 B 的子類。
4 .元素 A 是接口 B 的實現。
幸運的是,目前已經有大量的框架幫助我們降低我們系統的耦合度。比如,使用 struts 我們可以應用 MVC 模型,使頁面展現與業務邏輯分離,做到了頁面展現與業務邏輯的低耦合。當我們的頁面展現需要變更時,我們只需要修改我們的頁面,而不影響我們的業務邏輯;同樣,我們的業務邏輯需要變更的時候,我們只需要修改我們的 java 程序,與我們的頁面無關。使用 spring 我們運用 IoC (反向控制),降低了業務邏輯中各個類的相互依賴。假如類 A 因為需要功能 F 而調用類 B ,在通常的情況下類 A 需要引用類 B ,因而類 A 就依賴于類 B 了,也就是說當類 B 不存在的時候類 A 就無法使用了。使用了 IoC ,類 A 調用的僅僅是實現了功能 F 的接口的某個類,這個類可能是類 B ,也可能是另一個類 C ,由 spring 的配置文件來決定。這樣,類 A 就不再依賴于類 B 了,耦合度降低,重用性提高了。使用 hibernate 則是使我們的業務邏輯與數據持久化分離,也就是與將數據存儲到數據庫的操作分離。我們在業務邏輯中只需要將數據放到值對象中,然后交給 hibernate ,或者從 hibernate 那里得到值對象。至于用 Oracle 、 MySQL 還是 SQL Server ,如何執行的操作,與我無關。
但是,作為優秀的開發人員,僅僅依靠框架提供的降低軟件耦合的方法是遠遠不夠的。根據我的經驗,以下一些問題我們應當引起注意:
1) 根據可能的變化設計軟件
我們采用職責驅動設計,設計中盡力做到“低耦合、高內聚”的一個非常重要的前提是,我們的軟件是在不斷變化的。如果沒有變化我們當然就不用這么費勁了;但是如果有變化,我們希望通過以上的設計,使我們在適應或者更改這樣的變化的時候,付出更小的代價。這里提供了一個非常重要的信息是,我們努力降低耦合的是那些可能發生變更的地方,因為降低耦合是有代價的,是以增加資源耗費和代碼復雜度為代價的。如果系統中某些元素不太可能變更,或者降低耦合所付出的代價太大,我們當然就應當選擇耦合。有一次我試圖將我的表現層不依賴于 struts ,但發現這樣的嘗試代價太大而失去意義了。對于軟件可能變更的部分,我們應當努力去降低耦合,這就給我們提出一個要求是,在軟件設計的時候可以預判日后的變化。根據以往的經驗我認為,一個軟件的業務邏輯和采用的技術框架往往是容易變化的 2 個方面。客戶需求變更是我們軟件設計必須考慮的問題。在 RUP 的開發過程中,為什么需要將分析設計的過程分為分析模型和設計模型,愚以為,從分析模型到設計模型的過程實際上是系統從滿足直接的客戶需求到優化系統結構、適應可預見的客戶需求變更的一個過程。這種客戶需求的變更不僅僅指對一個客戶需求的變更,更是指我們的軟件從適應一個客戶需求到適應更多客戶需求的過程。另一個方面,現在技術變更之快, EJB 、 hibernate 、 spring 、 ajax ,一個一個的技術像走馬燈一樣從我們腦海中滑過,我們真不知道明天我在用什么。在這樣的情況下,適應變化就是我們最佳的選擇。
2) 合理的職責劃分
合理的職責劃分,讓系統中的對象各司其職,不僅是提高內聚的要求,同時也可以有效地降低耦合。比如評審計劃 BUS 、評審表 BUS 、評審報告 BUS 都需要通過評審計劃 DAO 去查詢一些評審計劃的數據,如果它們都去直接調用評審計劃 DAO (如圖 A ),則評審計劃 BUS 、評審表 BUS 、評審報告 BUS 三個對象都與評審計劃 DAO 耦合,評審計劃 DAO 一旦變更將與這三個對象都有關。在這個實例中,實際上評審計劃 BUS 是信息專家(關于信息專家模式我將在后面討論),評審表 BUS 和評審報告 BUS 如果需要獲得評審計劃的數據,應當向評審計劃 BUS 提出需求,由評審計劃 BUS 提供數據(如圖 B )。經過這樣的調整,系統的耦合度就降低了。
3) 使用接口而不是繼承
通過對耦合的分析,我們不難發現,繼承就是一種耦合。如果子類 A 繼承了父類 B ,不論是直接或間接的繼承,子類 A 都必將依賴父類 B 。子類 A 必須使用在存在父類 B 的環境中,父類 B 不存在子類 A 就不能使用,這樣將影響子類 A 的可移植性。一旦父類 B 發生任何變更,更改或去掉一個函數名,或者改變一個函數的參數,都將導致子類 A 不得不變更,甚至重寫。假如父類 B 的子類數十上百個,甚至貫穿這個項目各個模塊,這樣的變更是災難性的。這種情況最典型的例子是我們現在使用 hibernate 和 spring 設計 DAO 對象的方式,具體的描述參見我寫的 《如何在 struts + spring + hibernate 的框架下構建低耦合高內聚的軟件結構》 一文。
總之,“低耦合”給軟件項目帶來的優點是:易于變更、易于重用。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
