耦合度的概念html
耦合度是對模塊(類)間關聯程度的度量,能夠用"聯繫"做同義詞,"獨立性"做反義詞。java
耦合度分類(由高到低)ajax
(1)內容耦合。當一個模塊直接修改或操做另外一個模塊的數據,或者直接轉入另外一個模塊時,就發生了內容耦合。此時,被修改的模塊徹底依賴於修改它的模塊。類與類之間直接調用或繼承關係都是屬於這種耦合。spring
需徹底避免內容耦合,重點在於不要在類內部直接操做另外一個類的對象的數據成員,能夠經過在操做類中增長一個函數接口向客戶類提供服務來實現數據庫
(2)公共耦合。兩個及兩個以上的模塊共同引用一個全局數據項就稱爲公共耦合。數據結構
(3)控制耦合。一個模塊在界面上傳遞一個信號(如開關值、標誌量等)控制另外一個模塊,接收信號的模塊的動做根據信號值進行調整,稱爲控制耦合。框架
(4)標記耦合。模塊間經過參數傳遞複雜的內部數據結構,稱爲標記耦合。此數據結構的變化將使相關的模塊發生變化。函數
(5)數據耦合。模塊間經過參數傳遞基本類型的數據,稱爲數據耦合。優化
(6)非直接耦合。模塊間沒有信息傳遞時,屬於非直接耦合。
spa
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的框架下構建低耦合高內聚的軟件結構》一文。