面向?qū)ο筮M行程序設(shè)計的時候有五大基本的原則,分別是:
1、單一職責(zé)原則(SRP)
2、開放封閉原則(OCP)
3、里氏替換原則(LSP)
4、依賴倒置原則(DIP)
5、接口隔離原則(ISP)
然后說一下依賴倒置原則,它的原始的定義包括兩個部分:
1、高層模塊不該依賴于底層模塊,它們都該依賴于抽象。
2、抽象不依靠于(具體)細節(jié),細節(jié)應(yīng)該依賴于抽象。
英文原文:Highlevel modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。
上面的抽象指的是接口或者抽象類。細節(jié)指的是具體的類。依賴這個詞,是一個對于多個事物來說的, 可以解釋為依靠。
比如在對象A中的方法中調(diào)用了對象B的方法或者熟悉,這就可以說是對象A依賴于對象B,因為對象A只有''依靠''對象B才能完成某些功能。
又比如,抽象類A或者中約定了一些公共方法,類B實現(xiàn)或者繼承了A,對它的細節(jié)進行了完善,那么這個B是依賴于A的,因為B的基本功能框架是通過A才能實現(xiàn)的。
所以一般如果沒有考慮依賴倒置的設(shè)計,對象和對象之間的依賴是一種直接的依賴,這是一種緊耦合的設(shè)計,當被依賴的一方發(fā)生變化的時候,依賴的一方也需要被迫進行改變。
自頂而下的程序設(shè)計中,通常會將某個業(yè)務(wù)邏輯劃分成為一個模塊,而它的實現(xiàn)是通過一些粒度比較小的功能點進行完成的,小的功能點又可以由更小的功能實現(xiàn),在面向?qū)ο蟮木幊讨校恳粋€都是對象,所以高層模塊的功能是通過許多底層模塊的功能實現(xiàn)的,高層模塊調(diào)用底層模塊,也就是高層模塊依賴于底層模塊。
之前說過了,這樣的直接依賴,將會使得兩者之間產(chǎn)生強耦合,一般底層模塊是比較細節(jié)的,而細節(jié)的東西變化比較頻繁,所以底層模塊一旦需要變化了,由于高層模塊是直接依賴于底層的,那么高層模塊也必須改變,而開閉原則所要求的是程序?qū)π薷年P(guān)閉,對擴展開放。而且頻繁的修改高層模塊的代碼,也會很容易引入錯誤。
所以為了解決這個問題,可以對于具體的實現(xiàn)類加上抽象,它們的依賴關(guān)系不通過具體的實現(xiàn)類,而是抽象之間的依賴,這樣的話,細節(jié)的類需要變化了,不影響高層模塊類的使用,因為對于高層的模塊(或者說是原來依賴方)來說,它看到的只是抽象,具體的實現(xiàn)細節(jié)它是看不見的。而抽象是比較穩(wěn)定的,不會發(fā)生變化。所以高層的模塊不需要改變。
依賴倒置的核心其實是面向接口編程,總結(jié)出來是如下幾個原則。
1、盡量不要用直接依賴,而是通過抽象進行依賴,即每個類最好有抽象。
2、依賴關(guān)系的對象引用變量用抽象的類型。
3、任何類不要從具體的類派生。
4、不要重寫基類的方法。
通過依賴倒置的設(shè)計,有利于并行的程序開發(fā),假如甲開發(fā)類A,乙開發(fā)類B,A依賴于B,那么當乙還沒有開發(fā)完成的時候,甲也沒辦法將A的開發(fā)繼續(xù)下去,因為沒辦法去測試其功能。而如果采用依賴倒置設(shè)計類的依賴的話,乙只需要提供B的抽象,而甲根據(jù)抽象就可以進行開發(fā)和測試。
依賴是可以進行傳遞的,java中提供了好幾種的傳遞依賴的方法,傳遞依賴就是指將所需要的被依賴對象注入到需要依賴內(nèi)。
1、通過構(gòu)造函數(shù)的參數(shù)申明來傳遞依賴對象。
2、通過set方法將依賴對象注入。
3、接口申明依賴對象,在接口定義的某個方法中,將依賴對象的抽象作為形參。
Spring的兩大特點是IOC和AOP,IOC叫做控制反轉(zhuǎn),AOP叫做面向切面編程。
之所以叫做控制反轉(zhuǎn),是因為通過沒有通過spring框架,一般的假如對象A依賴于對象B的話,如上所訴,會有一個依賴注入的過程,這種依賴注入的控制的主動權(quán)在我們,我們決定何時以何種方式進行注入,但是spring提供了ioc的容器,使得對象的生成以及對象依賴關(guān)系之間的依賴對象的注入由IOC容器來完成。反轉(zhuǎn)的真是對象注入的權(quán)利,現(xiàn)在有IOC容器來控制,所以IOC也稱為依賴注入DI,實際上,依賴注入是控制反轉(zhuǎn)的手段。