1.關於依賴和耦合:從小國寡民到和諧社會
在老子的「小國寡民」論中,提出了一種理想的社會狀態:鄰國相望,雞犬之聲相聞,民至老死,不相往來。這是他老人家的一種社會理想,老死不相往來的人群呈現了一片和諧景象。因為不發生瓜葛,也就無所謂關聯,進而無法導致衝突。這是先祖哲學中的至純哲理,但理想的大同總是和現實的生態有著或多或少的差距,人類社會無法避免聯絡的發生,所以小國寡民的理想成為一種美麗的夢想,不可實現。同樣的道理,對映到軟體「社會」中,也就是軟體系統結構中,也預示著不同的層次、模組、型別之間也必然存在著或多或少的聯絡,這種聯絡不可避免但可管理。正如人類社會雖然無法實現小國寡民,但是理想的狀態下我們推崇和諧社會,把人群的聯絡由複雜變為簡單,由曲折變為統一,同樣可以使得這種關聯很和諧。所以,軟體系統的使命也應該朝著和諧社會的目標前進,對於不同的關係處理,使用一套行之有效的哲學,把複雜問題簡單化,把僵化問題柔性化,這種哲學或者說方法,在我看來就是:依賴的哲學,也就是本文所要闡釋的中心思想。
因為「耦合是不可避免的」,所以首先就從認識依賴和耦合的概念開始,來一步步闡釋依賴的哲學思想。
(1)什麼是依賴和耦合
依賴,就是關係,代表了軟體實體之間的聯絡。軟體的實體可能是模組,可能是層次,也可能是具體的型別,不同的實體直接發生依賴,也就意味著發生了耦合。所以,依賴和耦合在我看來是對乙個問題的兩種表達,依賴闡釋了耦合本質,而耦合量化了依賴程度。因此,對於關係的描述方式,就可以從兩個方面的觀點來分析。
從依賴的角度而言,可以分類為:
· 無依賴,代表沒有發生任何聯絡,所以二者相互獨立,互不影響,沒有耦合關係。
· 單向依賴,關係雙方的依賴是單向的,代表了影響的方向也是單向的,其中乙個實體發生改變,會對另外的實體產生影響,反之則不然,耦合度不高。
· 雙向依賴,關係雙方的依賴是相互的,影響也是相互的,耦合度較高。
從耦合的角度而言,可以分類為(此處回歸到具體的**級耦合概念,以方便概念的闡釋):
· 零耦合,表示兩個類沒有依賴。
· 具體耦合,如果乙個類持有另乙個具體類的引用,那麼這兩個類就發生了具體耦合關係。所以,具體耦合發生在具體類之間的依賴,因此具體類的變更將引起對其關聯類的影響。
· 抽象耦合,發生在具體類和抽象類的依賴,其最大的作用就是通過對抽象的依賴,應用物件導向的多型機制,實現了靈活的擴充套件性和穩定性。
不同的耦合,代表了依賴程度的差別,以「粒度」為概念來分析其耦合的程度。引用中間層來分離耦合,可以使設計更加優雅,架構更加富有柔性,但直接的依賴也存在其市場,過度的設計也並非可取之道。因為,效率與效能同樣是設計需要考量的因素,過多的不必要分離會增加呼叫的次數,造成效率浪費。
後文分析依賴倒置原則的弊端之一正是對此問題的進一步闡述。
(2)耦合是如何產生的
那麼,軟體實體之間的耦合是如何產生呢?回歸每天揮灑的**片段,其實就是在重複的創造著耦合,並且得益於對這種耦合帶來的資料通訊。如果將歷史的目光回歸到軟體設計之初,人類以簡單的機器語言來實現最簡單的邏輯,給乙個輸入,實現乙個輸出,可以表達為如圖3-1所示的形式。
隨著軟體世界的革命,業務邏輯的複雜,以上的簡單化處理已經不足以實現更複雜的軟體產品,當系統內部的複雜度超越人腦可識別的程度時,就需要通過更科學的方法或者方式來梳理,如圖3-2所示。
因此,人類開始發揮重組和簡單化處理的優勢,開發者不得不在軟體設計上做出平衡。平衡的結果就是通過對複雜的系統模組化,把複雜問題簡單處理,從而達到能夠被人腦識別的目的。基於這種指導原則,隨著複雜度的增加模組的劃分更加朝著精細化發展,尤其是物件導向程式設計理論的出現,使得對複雜的處理實現了更科學的理論基礎。然而,複雜的問題可以通過劃分實現簡單的功能模組或者技術單元,但由此應運而生的子單元會越來越多,而且越來越多的子單元必須發生資料的通訊才能完成統一的業務處理,所以產生的資料通訊管理也越來越多。對於子單元的管理,也就是本文關注的核心概念——依賴,成為新的軟體設計問題,那麼總結前人的經驗,提煉今人的智慧型,對耦合的產生做如下歸納:
· 繼承
· 聚合
· 介面
· 方法呼叫和引用
· 服務呼叫
了解了耦合發生的一般方式,就可以進入核心思想的討論,那就是在認識和了解依賴的基礎上,最終追求的目標。
話說
設計的目標:高內聚(high cohesion)、低耦合(low coupling)。
討論了半天,終於是時候對依賴和耦合進行一點兒總結了,也是該進行一點目標訴求了。在軟體設計領域,有那麼幾個至高原則值得每個開發者銘記於心,它們是:
· 面向抽象程式設計
· 低耦合,高內聚
· 封裝變化
· 實現重用:**重用、演算法重用
對了,就是這些平凡的字眼,匯集了物件導向思想的核心內容,也是本文力求闡釋的禪意心經。關於面向抽象程式設計和封裝變化,會在後面詳細闡釋,在此我們需要將注意力關注於「低耦合,高內聚」這一目標。
低耦合,代表了實現最簡單的依賴關係,盡可能地減少類與類、模組與模組、層次與層次、系統與系統之間的聯絡。低耦合,體現了人類追求簡單操作的理想狀態,按照軟體開發的基本實現技巧來追求軟體實體之間的關係簡單化,正是大部分設計模式力圖追求的目標;低耦合,降低了乙個類或乙個模組發生修改對其他類或模組造成的影響,將影響範圍簡單化。在本文闡釋的依賴關係方式中,實現單向的依賴,實現抽象的耦合,都是實現低耦合的基礎條件。
高內聚,一方面代表了職責的統一管理,一方面體現了關係的有效隔離。例如單一職責原則其實歸根結底是對功能性的一種指導性體現,將功能緊密聯絡的職責封裝為乙個類(或模組),而判斷的準則正是基於引起類變化的原因。所以,封裝離不開依賴,而抽象離不開變化,二者的概念和本質都是相對而言的。因此,高內聚的目標體現了以隔離為目標進行統一管理的思想。
那麼,為了達到低耦合、高內聚的目標,通常意義上的設計原則和設計模式其實都是朝著這個方向實現的,因此僅僅總結並非普遍意義的規則:
· 盡可能實現單項依賴。
· 不需要進行資料交換的雙方,不要實現多此一舉的關聯,人們將此形象稱為「不要向陌生人說話(don't talk to strangers)」。
· 保持內部的封裝性,關聯的雙方不要深入實現細節進行通訊,這是保證高內聚的必需條件。
本文節選自《你必須知道的.net(第2版)》一書
圖書詳細資訊:
什麼是抽象?
概述 a 抽象類和抽象方法必須用abstract關鍵字修飾 b 抽象類中不一定有抽象方法,但是有抽象方法的類必須定位為抽象類 c 抽象類不能例項化 因為他不是具體的,抽象類也有構造方法,但是不能例項化,那麼構造方法的作用是什麼呢?用於子類訪問父類資料的初始化。d 抽象類的子類問題 a 如果不想重寫抽...
什麼是抽象?
1.抽象類的定義 抽象就是從多個事物中將共性的,本質的內容抽取出來。2.抽象方法的由來 多個物件都具備相同的功能,但是功能具體內容有所不同,那麼在抽取過程中,只抽取了功能定義,並未抽取功能主體,那麼只有功能宣告,沒有功能主體的 方法稱為抽象方法。2.1例子 例如 狼和狗都有吼叫的方法,可是吼叫內容是...
什麼是抽象類?什麼是抽象方法?
抽象類 抽象類就是不能使用new方法進行例項化的類,即沒有具體例項物件的類,抽象類有點類似於 模板 的作用,目的是根據其格式來建立和修改新的類,物件不能由抽象類直接建立,只可以通過抽象類派生出新的子類,再由其子類來建立物件,當乙個類被宣告為抽象類時,要在這個類前面加上修飾符abstract,在抽象類...