Dependency Injection 經常簡稱爲:DI。html
它是實現控制反轉(Inversion of Control – IoC)的一個模式。web
fowler 大大大神 「幾十年」前的經典文章 https://www.martinfowler.com/articles/injection.html 說的很清楚。面試
「幾十年」以來,相信你們都早已學會了 大大大神 的教典。數據庫
咱們簡單回憶一下對應內容,以便咱們能夠順利進入後續章節:徒手擼個小DI。框架
文章內容大體是這樣:函數
首先舉例:性能
public interface MovieFinder { List findAll(); } class MovieLister { private MovieFinder finder; public MovieLister() { finder = new ColonDelimitedMovieFinder("movies1.txt"); } 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()]); }
而後大大大神吐槽了一堆:this
這個實現類的名字就說明:我將要從一個逗號分隔的文本文件中得到影片列表。你沒必要操心具體的實現細節,只要設想這樣一個實現類就能夠了。若是這個類只由我本身使用,一切都沒問題。可是,若是個人朋友歎服於這個精彩的功能,也想使用個人程序,那又會怎麼樣呢?若是他們也把影片清單保存在一個逗號分隔的文本文件中,而且也把這個文件命名爲」 movie1.txt 「,那麼一切仍是沒問題。若是他們只是給這個文件改更名,我也能夠從一個配置文件得到文件名,這也很容易。可是,若是他們用徹底不一樣的方式——例如SQL 數據庫、XML 文件、web service,或者另外一種格式的文本文件——來存儲影片清單呢?在這種狀況下,咱們須要用另外一個類來獲取數據。因爲已經定義了MovieFinder接口,我能夠不用修改moviesDirectedBy方法。可是,我仍然須要經過某種途徑得到合適的MovieFinder實現類的實例。插件
還有張依賴圖設計
MovieLister類既依賴於MovieFinder接口,也依賴於具體的實現類。咱們固然但願MovieLister類只依賴於接口,但咱們要如何得到一個MovieFinder子類的實例呢?
在Patterns of Enterprise Application Architecture一書中,咱們把這種狀況稱爲插件(plugin):MovieFinder的實現類不是在編譯期連入程序之中的,由於我並不知道個人朋友會使用哪一個實現類。咱們但願MovieLister類可以與MovieFinder的任何實現類配合工做,而且容許在運行期插入具體的實現類,插入動做徹底脫離我(原做者)的控制。這裏的問題就是:如何設計這個鏈接過程,使MovieLister類在不知道實現類細節的前提下與其實例協同工做。
將這個例子推而廣之,在一個真實的系統中,咱們可能有數十個服務和組件。在任什麼時候候,咱們總能夠對使用組件的情形加以抽象,經過接口與具體的組件交流(若是組件並無設計一個接口,也能夠經過適配器與之交流)。可是,若是咱們但願以不一樣的方式部署這個系統,就須要用插件機制來處理服務之間的交互過程,這樣咱們纔可能在不一樣的部署方案中使用不一樣的實現。因此,如今的核心問題就是:如何將這些插件組合成一個應用程序?這正是新生的輕量級容器所面臨的主要問題,而它們解決這個問題的手段無一例外地是控制反轉(Inversion of Control)模式。
學術一點就是說 避免類之間強耦合,咱們須要用依賴注入等方式在運行時才創建依賴達到代碼鬆耦合,從而使代碼易爲維護
戲言就是在說:
因此上述代碼中:
我(MovieLister)離不開了 你 (ColonDelimitedMovieFinder("movies1.txt")),
可是咱們男人必須靠本身,至少表面沒人看出咱們之間的關係
只有從咱們(MovieLister)身體裏面沒有了你,才能沒人看出咱們之間的關係
當咱們開始幹活的時候,咱們再根據咱們的私下關係協調好工做,男女搭配,好好幹活。
說到這裏, 各位要被面試的同窗記好這些話, 不要被問到依賴注入幫我解決了什麼事情的時候, 回一句 咱們不用本身new 對象啦, 這樣你們就不會看見面試官無語又懵逼的臉了。
class MovieLister { private IMovieFinder finder; public MovieLister(IMovieFinder finder) { this.finder = finder; } }
class MovieLister { [Inject] public IMovieFinder Finder { get; set;} }
public interface InjectFinder { void injectFinder(MovieFinder finder); } class MovieLister : InjectFinder { private IMovieFinder finder; public void injectFinder(MovieFinder finder) { this.finder = finder; } }
這幾種方式之間並無性能或者什麼特別的優點,主要是形式上的差別。
具體對比能夠參考 http://insights.thoughtworkers.org/injection/