手把手教你写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框架有什么?

引用参考:

相关文章
相关标签/搜索