Angular4学习笔记(四)- 依赖注入

概念

依赖注入是一种设计思想,并非某一类语言所特有的,所以能够参考开涛大神关于学习Java语言的Spring框架时对其的解释:html

DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并不是为软件系统带来更多功能,而是为了提高组件重用的频率,并为系统搭建一个灵活、可扩展的平台。经过依赖注入机制,咱们只须要经过简单的配置,而无需任何代码就可指定目标须要的资源,完成自身的业务逻辑,而不须要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为何须要依赖,谁注入谁,注入了什么”,那咱们来深刻分析一下:segmentfault

  • 谁依赖于谁:固然是应用程序依赖于IoC容器;
  • 为何须要依赖:应用程序须要IoC容器来提供对象须要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所须要的外部资源(包括对象、资源、常量数据)。

IoC和DI由什么关系呢?其实它们是同一个概念的不一样角度描述,因为控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),因此2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”1数组

Angular中的依赖注入

Angular中能够在app.module.ts中进行全局声明,也能够在组件内部根据特定需求实现特定声明。
声明是经过属性providers实现的,顾名思义,它是一个对象提供者,复数形式表名其为数组形式。且子类型为Provide,它位于@angular/core中,实现以下:app

export interface TypeProvider extends Type<any> {
}
export interface ValueProvider {
  provide: any;
  useValue: any;
  multi?: boolean;
}
export interface ClassProvider {
  provide: any;
  useClass: Type<any>;
  multi?: boolean;
}
export interface ExistingProvider {
  provide: any;
  useExisting: any;
  multi?: boolean;
}
export interface FactoryProvider {
  provide: any;
  useFactory: Function;
  deps?: any[];
  multi?: boolean;
}

export declare type Provider =
  TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[];

能够看到,Provider共有5个明确的子类,也决定了其使用方式的数量。因为全局声明和组件内部声明的方式差异不大,可见的区别是在app.module.ts中属性providers是在模块注解@NgModule中声明而组件中是经过注解@Component声明。所以实现方式不对全局和组件加以区分。框架

因为是初学,此处仅列举经常使用的几种方式:useClassuseFactoryuseValuedom

useClass

providers: [{provide: DefaultBookService, useClass: DefaultBookService}]
其中provide定义了token,而useClass则指明了使用的类,此处因为token和实现类相同,均为DefaultBookService所以能够简写为providers: [DefaultBookService]ide

useFactory

providers: [{
    provide: DefaultBookService, useFactory: () => {
      const rdm = Math.random() < 0.5;
      if (rdm) {
        return new DefaultBookService();
      } else {
        return new HuaZhangBookService();
      }
    }

HuaZhangBookServiceDefaulteBookService的一个子类。根据状况返回所需注入的对象。函数

若是经过依赖注入的对象同时依赖另外一个经过依赖注入的对象应如何实现呢?好比DefaultBookService,它的构造函数为:
constructor(public logger: LoggerService) { },而LoggerService也是经过依赖注入-即不须要本身手工new LoggerService()-时应该怎么办?在类FactoryProvider中提供了一个名叫deps的参数,它能够帮助咱们实现依赖对象的引用。用法以下:学习

providers: [{
    provide: DefaultBookService, useFactory: (logger: LoggerService) => {
      const rdm = Math.random() < 0.5;
      if (rdm) {
        return new DefaultBookService(logger);
      } else {
        return new HuaZhangBookService(logger);
      }
    }, deps: [LoggerService]
  }, LoggerService]

deps是一个任意类型的数组,为何呢,由于类的参数不会只有一个,当构造方法中有多个参数时,可同时依赖多个不一样类型的对象。this

useValue

基本用法:
{provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5}
扩展用法:

providers: [{
    provide: DefaultBookService, useFactory: (logger: LoggerService, isDev) => {
      if (isDev) {
        return new DefaultBookService(logger);
      } else {
        return new HuaZhangBookService(logger);
      }
    }, deps: [LoggerService, 'IS_DEV_ENV']
  },
    LoggerService, {provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5}
  ]

能够看到,在useFactory的箭头表达式中有两个参数,他们依次对应deps中的token,即isDev对应token为IS_DEV_ENV的对象,而它正是使用了本小节中所涉及的useValue形式,它返回一个boolean对象。

另外须要注意的是,token不止能指定特定的类,也能够指定特定的值。

multi

参考

其余

  • 以上咱们简单介绍了几种Angular实现依赖注入的方式,可是还须要提供使用它的条件,在Angular中,只有当组件或者服务被注解@Injectable或其子类如@Component修饰后,才可以使用,建议不管是否使用依赖注入,都使用@Injectable修饰。
  • 能够经过构造方法的参数来放置经过依赖生成的对象:constructor(private bookService: DefaultBookService) { },此时,其余方法中直接使用this.bookService来调用DefaultBookService中的方法了。
  • 经过依赖注入传入的对象,能够经过Injector来进行访问,它位于@angular/core包中,所以上面的构造方法能够这样声明constructor(private injector: Injector) { },经过this.injector.get(DefaultBookService)来获取DefaultBookService对象并调用其中的方法,但不建议这样作,由于不如直接传入所需对象来的明确。
  • app.module.ts中使用useFactory而且使用箭头表达式来实现时,注册的组件会报错,至今无解,相关问题已发至segmentFault,哪位大神若是知道,烦请告诉,跪谢。
  • 关于Token的学习能够参考Angular 4 依赖注入教程之八 InjectToken的使用

  1. 若是想要更加深刻的了解IoC和DI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html。

相关文章
相关标签/搜索