這篇文章主要介紹了PHP物件導向五大原則之依賴倒置原則(DIP),簡單講述了依賴倒置原則的概念、原理並結合執行個體形式分析了php依賴倒置原則相關定義與使用方法,需要的朋友可以參考下
本文執行個體講述了PHP物件導向五大原則之依賴倒置原則(DIP)。分享給大家供大家參考,具體如下:
什麼是依賴倒置呢?簡單地講就是將依賴關係倒置為依賴介面,具體概念如下:
1.上層模組不應該依賴於下層模組,它們共同依賴於一個抽象(父類不能依賴子類,它們都要依賴於抽象類別)
2.抽象不能依賴於具體,具體應該要依賴於抽象。
注意,這裡的介面不是狹義的介面。
為什麼要依賴介面?因為介面體現對問題的抽象,同時由於抽象一般是相對穩定的或者是相對變化不頻繁的,而具體是易變的。因此依賴抽象是實現代碼擴充和運行期內綁定(多態)的基礎:只要實現了該抽象類別的子類,都可以被類的使用都使用。這裡,強調一下擴充性這個概念。通常擴充性指對已知行為的擴充,在講述介面時,也提到過,介面應該是相對的。這就告訴我們,無論使用多麼先進的設計模式,也無法做到不需要修改代碼即可達到不變應萬變的地上。在物件導向的這五大原則裡,我認為依賴倒置是最難理解,也是最難實現的。
這裡以僱員類為例
<?phpinterface employee{ public function working();}class teacher implements employee{ public function working() { echo 'teaching...'; }}class coder implements employee{ public function working() { echo 'coding...'; }}class workA{ public function work() { $teacher = new teacher(); $teacher->working(); }}class workB{ private $e; public function set(employee $e) { $this->e = $e; } public function work() { $this->e->working(); }}$worka = new workA;$worka->work();$workb = new workB;$workb->set(new teacher());$workb->work();
在workA中,work方法依賴於teacher實現;在workB中,work轉而依賴抽象,這樣可以把需要的對象通過參數傳入。上述代碼通過介面,實現了一定程度的解耦,但仍然是有限的。不僅是使用介面,使用工廠等也能實現一定程度的解耦和依賴倒置。
在workB中,teacher執行個體通過set方法傳入,從而實現了原廠模式。由於這樣的實現仍然是硬式編碼,為了實現代碼的進一步擴充,把這個依賴關係寫在設定檔裡,指明workB需要一個teacher對象,專門由一個程式配置是否正確(如所依賴的類檔案是否存在)以及載入配置中所依賴的實現,這個檢測程式,就稱為IOC容器。
很多文章裡看到IOC(Inversion of Control)概念,實際上,IOC是依賴倒置原則(Dependence Inversion Principle,DIP)的同義字。而在提IOC的時候,你可能還會看到有人提起DI等概念。DI,即依賴注入,一般認為,依賴注入(DI)和依賴尋找(DS)是IOC的兩種實現。不過隨著某些概論的演化,這幾個概念之間的關係也變得很模糊,也有人認為IOC就是DI。有人認為,依賴注入的描述比起IOC來更貼切,這裡不糾纏於這幾個概念之間的關係。
在經典的J2EE設計裡,通常把DAO層和Servicen層細分為介面層和實現層,然後在設定檔裡進行所依賴關係的配置,這是最常見的DIP的應用。Spring架構就是一個很好的IOC容器,把控制權從代碼剝離到IOC視窗,這裡是通過XML設定檔實現的,Spring在執行期間根據設定檔的設定,建立對象之間的依賴關係。
如下面的代碼所示
<bean scopre="prototype" class="cn.notebook.action.NotebookListOtherAction" id="notebookListOtherAction"> <property ref="userReplyService" name="userReplyService" /> <property ref="userService" name="userService" /> <property ref="permissionService" name="permissionService" /> <property ref="friendService" name="friendService" /></bean>
但是這樣的設定一樣存在問題,設定檔會變得越來越大,其間關係會越來越複雜。同樣逃脫不了隨著應用和業務的改變,不斷修改代碼的惡魘(這裡認為設定檔是代碼的一部分。並且在實際開發中,很少存在單純修改設定檔的情況。一般設定檔修改了,代碼也會做相應的修改)
在PHP裡,也有類似模仿Spring的實現,即把依賴關係寫在了設定檔裡,通過設定檔來產生需要的對象。我覺得這樣的代碼還是為了實現而實現。在Srping裡,設定檔裡配置的不僅僅是一個類運行時的依賴關係,還可以實現交易管理、AOP、消極式載入等。而PHP要實現上面的種種特性,其消耗是巨大的。從語言層面講,PHP這種動態指令碼語言在實現一些多態特性上和編譯型的語言不同。其次PHP作為敏捷性的開發語言,更強調快速開發、邏輯清晰、代碼更簡單易懂,如果再附加了各種設計模式的架構,從技術實現和運行效率上來看,都是不可取的。依賴倒置的核心原則是解耦。如果脫離這個最原始的原則,那就是本末倒置。
事實上,很多的設計模式裡已經隱含了依賴倒置原則我們也在有意無意地做著一些依賴反轉的工作。只是作為PHP,目前還沒有一個比較完善的IOC容器,或許是PHP根本不需要。
如果滿足DIP:
1.每個較高層次類都為它所需要的服務提出一個介面聲明,較低層次類實現實現這個介面。
2.每個高層次類都通過該抽象介面使用服務。