Angular 4 依赖注入教程之五 FactoryProvider配置依赖对象

目录

阅读须知

本系列教程的开发环境及开发语言:app

基础知识

Console 对象

Console 对象能够在任何全局对象中访问,如 WindowWorkerGlobalScope 以及经过属性工做台提供的特殊定义。在浏览器中咱们能够经过 Window.console 访问 console 对象,使用示例以下:

console.log('My nickname is semlinker');

FactoryProvider 的做用

FactoryProvider 用于告诉 Injector (注入器),经过调用 useFactory 对应的函数,返回 Token 对应的依赖对象。

FactoryProvider 接口

export interface FactoryProvider {
  // 用于设置与依赖对象关联的Token值,Token值多是Type、InjectionToken、
  // OpaqueToken的实例或字符串
  provide: any;
  // 设置用于建立对象的工厂函数
  useFactory: Function;
  // 依赖对象列表
  deps?: any[];
  // 用于标识是否multiple providers,如果multiple类型,则返回与Token关联的依赖
  // 对象列表
  multi?: boolean;
}

FactoryProvider的使用 这篇文章中,咱们已经介绍了 FactoryProvider 的一些相关知识。接下来咱们将介绍如何使用 FactoryProvider 配置依赖对象。

FactoryProvider

俗话说得好,温故而知新。咱们先来回顾一下上一节建立的 LoggerService 服务:

export class LoggerService {
    constructor(private enable: boolean) { }

    log(message: string) {
        if(this.enable) {
           console.log(`LoggerService: ${message}`);
        }
    }
}

LoggerService 的正确配置方式以下:

@NgModule({
   ...,
   providers: [
     HeroService,
     {
      provide: LoggerService, 
      useFactory: () => {
        return new LoggerService(true);
      }
    }
   ],
  bootstrap: [AppComponent]
})
export class AppModule { }

在继续介绍前,咱们先来了解一下 Angular 的一大特点:

跨平台开发

学习如何基于 Angular 构建应用程序,并复用代码和技能来构建适用于全部平台的应用。好比:Web应用、移动Web应用、原生移动应用和原生桌面应用等。

没错,Angular 框架的一大特点就是跨平台开发。回到正题,不知道读者有没有察觉到,在 LoggerService 类中的 log() 方法内,咱们是直接使用 console.log() 方法输出调试信息。虽然在大多数状况下,咱们的应用都是运行在浏览器环境下,但 console.log() 存在兼容性问题 (了解详细信息 - Can I Use)。除此以外,假如往后咱们的应用须要运行在其它平台下,就会出现问题。

为了解决上述问题,咱们能够建立一个 ConsoleService 服务,且该服务需实现统一的 Console 接口。但本文的重点不在这里,所以咱们先简单实现一个 ConsoleService 服务:

export class ConsoleService {
    log(message) {
        console.log(`ConsoleService: ${message}`);
    }
}

接下来咱们就须要更新先前的 LoggerService 服务:

export class LoggerService {
    constructor(private enable: boolean,
      consoleService: ConsoleService) { }

    log(message: string) {
        if (this.enable) {
            console.log(`LoggerService: ${message}`);
        }
    }
}

但当咱们更新完 LoggerService ,成功保存后,你会看到如下异常信息:

app.module.ts (27,16): Supplied parameters do not match any signature of call target.

这说明提供的参数与调用目标的签名不匹配,这是由于在 AppModule 中,LoggerService 的配置方式是:

{
  provide: LoggerService, 
  useFactory: () => {
    return new LoggerService(true);
}

而此时 LoggerService 构造函数输入参数的个数为两个,所以会抛出上面的异常。那么咱们应该怎么解决这个问题呢?这时咱们就要利用 FactoryProvider 接口中定义的 deps 属性,来声明 LoggerService 所依赖的对象。

配置 deps 属性

{
  provide: LoggerService, 
  useFactory: (consoleService) => {
    return new LoggerService(true, consoleService);
  },
  deps: [ConsoleService]
}

更新 AppModule

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

当更新完代码,而后再来一个华丽的保存操做,最后打开你的控制台,你又看到预期的输出信息:

LoggerService: Fetching heros...

我有话说

工厂函数是用来干吗的?

在现实生活中,工厂是用来生产产品的,如鞋子工厂用来生产鞋子。而 FactoryProvider 接口中 useFactory 属性对应的工厂函数就是用来建立依赖对象。此外生产一双鞋子也须要对应的材料,如鞋底、鞋带等,而建立依赖对象也可能须要依赖其它对象,所以 FactoryProvider 接口中定义了 deps 属性用来声明依赖对象列表。