IoC控制反转与DI依赖注入

IoC控制反转与DI依赖注入

IoC: Inversion of Control

IoC是一种模式。目的是达到程序的复用。下面的两篇论文是对IoC的权威解释:

一个对IoC形象化的描述,出自论文 http://www.digibarn.com/friends/curbow/star/XDEPaper.pdf 中的:

Don‘t call us, we’ll call you (Hollywood’s Law).
A tool should arrange for Tajo to notify it when
the user wishes to communicate some event to
the tool, rather than adopt an “ask the user for
a command and execute it” model.

当用户(人、程序)要使用一个工具的时候,让框架来激活这个工具,而不是让用户执行一些命令来激活它。

即,原则是,使用组件的地方,只需要知道要使用什么样的组件,它会来自某个地方,但不需要知道组件具体是谁。

按照这个原则开发的系统,实现了各组件之间相互依赖的解耦。即替换某个组件,不需要修改使用这个组件的组件。

在编程语言实现上,IoC所涉及的工作主要有:

  • 定义接口、虚类等规范约束。这是基础。
  • 开发具体的实现规范的组件。
  • 开发组件创建工厂。具体包括组件配置、组件创建等。
  • 开发组件管理器。具体包括缓存组件对象、将组件交给需要它的对象等。

IoC有很多具体的实现模式:

(1)Dependency Injection (DI) 依赖注入

组件管理器将组件注入到使用组件的对象中。

  • 构造函数方式注入。被注入的对象在构造器中传入。
  • 设值方法注入。通过setter方法注入。
  • 接口方法注入。需要被注入的类实现一个具体的接口,由一个注入器调用这个接口方法,完成组件注入。
// Java示例:接口方法注入
 
// 注入依赖的接口
public interface InjectFinder {
    void injectFinder(MovieFinder finder);
}
 
// 注入依赖的接口
public interface InjectFinderFilename {
    void injectFilename(String filename);
}
 
// 注入器接口
public interface Injector {
  public void inject(Object target);
}
 
// ==
 
// 仅为InjectFinder组件
class MovieLister implements InjectFinder {
  public void injectFinder(MovieFinder finder) {
      this.finder = finder;
  }
}
 
// 既是InjectFinderFilename组件,又是InjectFinder接口的注入器
class ColonMovieFinder implements Injector, InjectFinderFilename {
  public void injectFilename(String filename) {
      this.filename = filename;
  }
 
  public void inject(Object target) {
    ((InjectFinder) target).injectFinder(this);        
  }
}
 
// 仅为InjectFinderFilename接口的注入器
class FinderFilenameInjector implements Injector {
    public void inject(Object target) {
      ((InjectFinderFilename)target).injectFilename("movies1.txt");      
    }
}
 
// ==
 
class Tester {
 
  private Container container;
 
  private void configureContainer() {
     container = new Container();
     // 注册组件。完成创建组件。
     registerComponents();
     // 注册注入器。完成组件注入。
     registerInjectors();
     container.start();
  }
 
  private void registerComponents() {
    // 这里模式是 组件名 - 组件
    container.registerComponent("MovieLister", MovieLister.class);
    container.registerComponent("MovieFinder", ColonMovieFinder.class);
  }
 
  private void registerInjectors() {
    // 这里的模式是 注入接口 - 注入器
    // 容器会遍历所有的组件,如果组件实现了注入接口,将调用对应的注入器,将这个组件作为参数,传递给注入器
    container.registerInjector(InjectFinder.class, container.lookup("MovieFinder"));
    container.registerInjector(InjectFinderFilename.class, new FinderFilenameInjector());
  }
 
  public static void main(String[] args) {
    configureContainer();
    MovieLister lister = (MovieLister)container.lookup("MovieLister");
    Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
    assertEquals("Once Upon a Time in the West", movies[0].getTitle());
  }
 
}

(2)Service Locator 服务定位器

组件管理器将组件交给一个全局的服务者。组件的使用者主动向这个全局的服务者索取需要的组件。

参考

本文首发于:http://farmersay.com/wiki/doku.php?id=2015:01:ioc_di

本文链接:http://www.cnblogs.com/afarmer/p/4259133.html

你可能感兴趣的:(依赖注入)