• 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://www.cnblogs.com/afarmer/p/4259133.html

  • 相关阅读:
    GCD and LCM HDU 4497 数论
    c++ const 修饰变量位置含义
    洛谷 P1017 进制转换
    洛谷 P1029 最大公约数和最小公倍数问题
    Buses and People CodeForces 160E 三维偏序+线段树
    Python学习-第三天-面向对象编程基础
    Python学习-第二天-字符串和常用数据结构
    关于Python学习的一点说明
    Python学习-第一天-函数和模块的使用
    Super Mario HDU 4417 主席树区间查询
  • 原文地址:https://www.cnblogs.com/afarmer/p/4259133.html
Copyright © 2020-2023  润新知