手把手教你寫DI_0_DI是什麼?

DI是什麼?

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)模式。

學術一點就是說 避免類之間強耦合,咱們須要用依賴注入等方式在運行時才創建依賴達到代碼鬆耦合,從而使代碼易爲維護

戲言就是在說:

  1. 咱們都是大忙人,請你做爲一個類簡單明瞭的說清楚 : 你這個類能幹什麼事? 不要讓咱們這些大忙人把你每件衣服一件一件看完了才知道你是木匠, 仍是鐵匠
  2. 咱們都是大老闆,咱們財產不能全靠你一個,你不能幹活或者你幹很差活,咱們作老闆的人必須能找人換了你

因此上述代碼中:

我(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/

下一章: 手把手教你寫DI_1_DI框架有什麼?

引用參考:

相關文章
相關標籤/搜索