您好,登錄后才能下訂單哦!
這篇文章主要介紹了php用依賴注入的原因,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
0. 前言
在軟件工程領域,依賴注入(Dependency Injection)是用于實現控制反轉(Inversion of Control)的最常見的方式之一。本文主要介紹依賴注入原理和常見的實現方式,重點在于介紹這種年輕的設計模式的適用場景及優勢。
1. 為什么需要依賴注入
控制反轉用于解耦,解的究竟是誰和誰的耦?這是我在最初了解依賴注入時候產生的第一個問題。
下面我引用Martin Flower在解釋介紹注入時使用的一部分代碼來說明這個問題。
public class MovieLister { private MovieFinder finder; public MovieLister() { finder = new MovieFinderImpl(); } public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); } ... }
public interface MovieFinder { List findAll(); }
我們創建了一個名為MovieLister的類來提供需要的電影列表,它moviesDirectedBy方法提供根據導演名來搜索電影的方式。真正負責搜索電影的是實現了MovieFinder接口的MovieFinderImpl,我們的MovieLister類在構造函數中創建了一個MovieFinderImpl的對象。
目前看來,一切都不錯。但是,當我們希望修改finder,將finder替換為一種新的實現時(比如為MovieFinder增加一個參數表明Movie數據的來源是哪個數據庫),我們不僅需要修改MovieFinderImpl類,還需要修改我們MovieLister中創建MovieFinderImpl的代碼。
這就是依賴注入要處理的耦合。這種在MovieLister中創建MovieFinderImpl的方式,使得MovieLister不僅僅依賴于MovieFinder這個接口,它還依賴于MovieListImpl這個實現。 這種在一個類中直接創建另一個類的對象的代碼,和硬編碼(hard-coded strings)以及硬編碼的數字(magic numbers)一樣,是一種導致耦合的壞味道,我們可以把這種壞味道稱為硬初始化(hard init)。同時,我們也應該像記住硬編碼一樣記住,new(對象創建)是有毒的。
Hard Init帶來的主要壞處有兩個方面:1)上文所述的修改其實現時,需要修改創建處的代碼;2)不便于測試,這種方式創建的類(上文中的MovieLister)無法單獨被測試,其行為和MovieFinderImpl緊緊耦合在一起,同時,也會導致代碼的可讀性問題(“如果一段代碼不便于測試,那么它一定不便于閱讀。”)。
2. 依賴注入的實現方式
依賴注入其實并不神奇,我們日常的代碼中很多都用到了依賴注入,但很少注意到它,也很少主動使用依賴注入進行解耦。這里我們簡單介紹一下賴注入實現三種的方式。
2.1 構造函數注入(Contructor Injection)
這是我認為的最簡單的依賴注入方式,我們修改一下上面代碼中MovieList的構造函數,使得MovieFinderImpl的實現在MovieLister類之外創建。這樣,MovieLister就只依賴于我們定義的MovieFinder接口,而不依賴于MovieFinder的實現了。
public class MovieLister { private MovieFinder finder; public MovieLister(MovieFinder finder) { this.finder = finder; } ... }
2.2 setter注入
類似的,我們可以增加一個setter函數來傳入創建好的MovieFinder對象,這樣同樣可以避免在MovieFinder中hard init這個對象。
public class MovieLister { s... public void setFinder(MovieFinder finder) { this.finder = finder; } }
2.3 接口注入
接口注入使用接口來提供setter方法,其實現方式如下。
首先要創建一個注入使用的接口。
public interface InjectFinder { void injectFinder(MovieFinder finder); }
之后,我們讓MovieLister實現這個接口。
class MovieLister implements InjectFinder { ... public void injectFinder(MovieFinder finder) { this.finder = finder; } ... }
最后,我們需要根據不同的框架創建被依賴的MovieFinder的實現。
3. 最后
依賴注入降低了依賴和被依賴類型間的耦合,在修改被依賴的類型實現時,不需要修改依賴類型的實現,同時,對于依賴類型的測試,可以更方便的使用mocking object替代原有的被依賴類型,以達到對依賴對象獨立進行單元測試的目的。
最后需要注意的是,依賴注入只是控制反轉的一種實現方式。控制反轉還有一種常見的實現方式稱為依賴查找。
感謝你能夠認真閱讀完這篇文章,希望小編分享php用依賴注入的原因內容對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,遇到問題就找億速云,詳細的解決方法等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。