迈向angularjs2系列(5):依赖注入

一: 为什么要依赖注入

1.构造器引入依赖

假设一个类Car类依赖于Engine(引擎)类、Transition(变速箱)类,可使用构造器来完成。

//类似如下代码
class Engine{}
 class Transmission{}
 class Car {
  engine;
  transmisssion;
  constructor(){
    this.engine=new Engine();
    this.transmisssion=new Transmission();
  }

构造函数创建似乎简洁明了,但是不灵活。Car类和其他两个类耦合度高,每当创建Car类,也会创建Engine类和Transmission类,它们的可测试性分别受到影响。

2.引入依赖注入

有后续的完善哦,这里只是简单的重构了一下。

class Engine{}
class Transmission{}
 @Injectable
//仅仅改动的地方
 class Car {
  engine;
  transmisssion;
  constructor(engine:Engine,transmission:Transmisson){
    this.engine=engine;
    this.transmisssion=transmission;
  }
 }

二: 配置注射器

在angular2中,使用注射器实现依赖注入机制。

完整的代码injector.ts:

import "reflect-metadata";
//引入 reflect-metadata 库来使用元数据反射 API:
import {
  Injector,Inject,Injectable,OpaqueToken,provide,ReflectiveInjector
} from "@angular/core";
const BUFFER_SIZE=new OpaqueToken("buffer-size");
//token常量,在整个应用里唯一、不可重复定义的值。
class Buffer{
  //@Inject装饰器接收依赖对象的token
  constructor(@Inject(BUFFER_SIZE) private size:Number){
    console.log(this.size);
  }
  //Buffer类接收依赖参数size
}
//使用生成的元数据解析依赖关系
@Injectable()
class Socket {
  constructor(private buffer:Buffer){}
}

const injector: Injector =
  ReflectiveInjector.resolveAndCreate([
    {provide: BUFFER_SIZE, useValue: '42'},
    Buffer,
    Socket
    ]);
//初始化注射器
injector.get(Socket);

1.导入

import "reflect-metadata";
import {
  Injector,Inject,Injectable,OpaqueToken,provide,ReflectiveInjector
} from "@angular/core";

2.token的定义和Inject装饰器接收token

const BUFFER_SIZE=new OpaqueToken("buffer-size");
BUFFER_SIZE这个常量,可以看做整个应用中唯一、不可重复定义的值。

3.使用生成的元数据解析依赖关系

@Injectable()
class Socket {
  constructor(private buffer:Buffer){}
}
Socket类用@Injectable()进行装饰,强制typescript编译器生成额外的元数据,用以描述指定的类能够注入哪些类型的依赖。这有点像angular1代码的压缩,一定要写成数组形式,以便压缩后的代码能够知道注入的是什么参数。
所以,如果省略掉装饰器,angular2的DI机制就不知道哪些符号对应的依赖关系需要进行注入了。
class Socket {
  constructor(@Inject(Buffer)private buffer:Buffer){}
}
//与上面代码等价哦

4.初始化注射器

const injector: Injector =
  ReflectiveInjector.resolveAndCreate([
    {provide: BUFFER_SIZE, useValue: '42'},
    Buffer,
    Socket
    ]);
//使用resolveAndCreate静态方法创建Injector类的实例

resolveAndCreate是一个工厂方法,可接收一个provider数组作为参数,返回值是一个新的Injector实例。

resolvede的意思是provider将会执行一次解析过程。

5.前向引用

如果Socket类定义在Buffer类之前呢,由于Js代码的从上往下执行,会报错说Buffer没有定义undefined。

那么除了用正确的顺序来定义它们之外,还有一种解决方案,前向引用。

import {forwardRef} from"@angular/core"
@Injectable()
class Socket {
  constructor(@Inject(forwardRef(()=>Buffer)) private buffer:Buffer){}
}
//前向引用唯一要做的就是使用@Inject装饰器,并把forwardRef函数的执行结果传给它。
forwardRef是一个高阶函数,只接收一个函数,并负责返回需要被注入的依赖。这可以算是延迟依赖类型解析的方案。而之前的模式时第一次实例化依赖符号就会被解析,默认情况下,声明类的时候就需要解析符号。

 

posted @ 2017-07-02 17:34  陈蒙的技术空间  阅读(270)  评论(0编辑  收藏  举报