深入理解Angular中的依赖注入(3)

```ts var inject = Injector.resolveAndCreate([ {provide: Render, useClass: DomRender} //{provide: Render, useClass: DomRender} // canvas 渲染方式 //{provide: Render, useClass: DomRender} // 服务的想染方式 ]) // 调用方不用做任何修改 class AppComponent { construtor(private render: Render) {} } ```

2. 值Provider

由于依赖的对象并不一定都是类,也可以是字符串、常量、对象等其他数据类型的,这可以方便用在全局变量、系统相关参数配置场景中。在创建Provider对象的时候,只需要使用useValue就可以声明一个值Provider:

```ts let freeMan = { freeJob: boolen; live: () => {return 'do something u cant do'} }; @Component({ // ... providers: [ {provide: 'someone', useValue: freeMan} ] }) ```

3. 别名Provider

有了别名Provider,我们就可以在一个Provider中配置多个令牌(Token),其对于的对象指向同一个实例,从而实现了多个依赖、一个对象实例的作用:

// ... providers: [ {provider: Power1, useClass: PowerService}, {provider: Power2, useClass: PowerService} ] // ...

仔细想想,这样对吗?

显然是不对的,如果两个都使用了useClass那么按照令牌,将会创建两个不同的实例出来,那么应该怎么实现两个令牌同一个实例呢?答案是使用useExistiong:

// ... providers: [ {provider: Power1, useClass: PowerService}, {provider: Power2, useExisting: PowerService} ] // ...

4. 工厂Provider

工厂Provider允许我们根据不同的条件来实例化不同的服务,比如,我们在开发环境需要打印日志,但是在实际部署的时候可能并不需要打印这些东西,那么我们总不可能去找到整个应用中所有的console.log()这样的方法吧,这个时候我们可以使用工厂provider来帮我们处理,我们只需要在工厂provider中设定一个条件,使其能够根据条件返回实例化我们需要的服务就可以了。为了实现这样的功能我们可以在根模块中这样注入:

```ts // app.module.ts @NgModule({ // ... providers: [ HeroService, ConsoleService, { provide: LoggerService, useFactory: (consoleService) => { return new LoggerService(true, consoleService); }, deps: [ConsoleService] } ], bootstrap: [AppComponent] }) export class AppModule { }

哦哦,那两个服务是这样写的:

// console.service.ts // ... export class ConsoleService { log(message) { console.log(`ConsoleService: ${message}`); } } // logger.service.ts // ... export class LoggerService { constructor(private enable: boolean, consoleService: ConsoleService ) { } log(message: string) { if (this.enable) { console.log(`LoggerService: ${message}`); } } }

然后在组件构造函数中写上需要的服务就好。

四、限定方式的依赖注入

想象一场景,你应用中的某个服务的provider被当做无效代码删掉了,那么你的应用可能就会出问题。还好这个问题早在设计的时候就已经考虑到了,我们可以使用Angular提供的@Optional和@Host装饰器来解决这个问题。

Optional可以兼容依赖不存在的情况,提高系统的健壮性;@Host可以限定查找规则,明确实例化的位置,避免一些莫名的共享对象问题。

@Optional

借助@Optional就可以实现可选注入:

// app.component.ts // ... import { Optional } from '@angular/core'; constructor(@Optional() private logger: LoggerService) { if (this.logger) { this.logger.log('i am choosed'); } }

像例子中的那样只需要在宿主组件(Host Component)的构造函数中增加@Optional装饰器即可。

需要注意的是,上面例子中的LoggerService并不是不存在,只是并没有根据providers元数据中配置被实例化出来。

@Host

Angular中依赖查找的规则是按照注入器从当前组件向父组件查找,直到找到要注入的依赖位置,如果找不到就会报错。我们可以使用Angular提供的@Host装饰器来解决 这个问题。

宿主组件如果一个组件注入了依赖项,那么这个组件就是这个依赖的宿主组件;如果这个组件通过<ng-content>被嵌入到了父组件,那这个父组件就是这个依赖的宿主组件。

1、宿主组件是当前组件

我们给组件构造函数加上@Host装饰器:

// ... @Component({ selector: 'parent', template: ` <h1>这里是父组件</h1> ` }) constructor( @Host() logger: LoggerService) {} // 加上@Host之后会报错,因为我们并没有在这个组件中注入LoggerService // 但是我们可以加上@Optional来避免报错 //@Host() //@Optional() //logger: LoggerService) {} )

2、宿主组件是父组件

我们修改一下上面的组件为父组件:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyfxgd.html