目录
- Angular 4 依赖注入教程之一 依赖注入简介
- Angular 4 依赖注入教程之二 组件服务注入
- Angular 4 依赖注入教程之三 ClassProvider的使用
- Angular 4 依赖注入教程之四 FactoryProvider的使用
- Angular 4 依赖注入教程之五 FactoryProvider配置依赖对象
- Angular 4 依赖注入教程之六 Injectable 装饰器
- Angular 4 依赖注入教程之七 ValueProvider的使用
- Angular 4 依赖注入教程之八 InjectToken的使用
阅读须知
本系列教程的开发环境及开发语言:
- Angular 4 +
- Angular CLI
- TypeScript
基础知识
Console 对象
Console 对象可以在任何全局对象中访问,如 Window
,WorkerGlobalScope
以及通过属性工作台提供的特殊定义。在浏览器中我们可以通过 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
属性用来声明依赖对象列表。