Angular 4 依赖注入教程之四 FactoryProvider的使用

前端之家收集整理的这篇文章主要介绍了Angular 4 依赖注入教程之四 FactoryProvider的使用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

目录

  • Angular 4 依赖注入教程之一 依赖注入简介

  • Angular 4 依赖注入教程之二 组件服务注入

  • Angular 4 依赖注入教程之三 ClassProvider的使用

  • Angular 4 依赖注入教程之四 FactoryProvider的使用

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

  • Angular 4 依赖注入教程之六 Injectable 装饰器

  • Angular 4 依赖注入教程之七 ValueProvider的使用

  • Angular 4 依赖注入教程之八 InjectToken的使用

  • @H_502_37@

    阅读须知

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

    • Angular 4 +

    • Angular CLI

    • TypeScript

    • @H_502_37@

      基础知识

      FactoryProvider 的作用

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

      FactoryProvider 的使用

      function serviceFactory() { 
          return new Service();
      }
      
      const provider: FactoryProvider = {
        provide: 'someToken',useFactory: serviceFactory,deps: []
      };

      FactoryProvider 接口

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

      FactoryProvider

      介绍完基础知识,接下来我们马上进入正题。不知道大家是否还记得,之前我们创建过的 HeroComponent 组件:

      import { Component,OnInit } from '@angular/core';
      import { HeroService } from '../hero.service';
      
      @Component({
        selector: 'app-hero',template: `
          <ul>
            <li *ngFor="let hero of heros">
              ID: {{hero.id}} - Name: {{hero.name}}
            </li>
          </ul>
        `
      })
      export class HeroComponent implements OnInit {
      
        constructor(private heroService: HeroService) { }
      
        heros: Array<{ id: number; name: string }>;
      
        ngOnInit() {
          this.heros = this.heroService.getHeros();
        }
      }

      那么现在问题来了,假设我们想在获取英雄数据时,输出调试信息,那应该怎么办?What ~,这个问题不是很简单么,直接使用 console.log API 输出相应信息不就行了么:

      console.log('Fetching heros...');
      this.heros = this.heroService.getHeros();

      那问题又来了,如果多个组件都使用 HeroService获取英雄数据,那么是不是每个组件都得添加对应的语句。另外如果要修改输出的调试信息,那就得修改程序中多个地方。其实我们一般只需要在开发阶段,输出调试信息,因此上面的方案不合理,也不够灵活。

      其实我们可以借鉴之前引入 HeroService 服务的思路,创建一个 LoggerService解决上面提到的问题。

      创建 LoggerService 服务

      export class LoggerService {
          constructor(private enable: boolean) { }
      
          log(message: string) {
              if(this.enable) {
                 console.log(`LoggerService: ${message}`);
              }
          }
      }

      配置 LoggerService 服务

      @NgModule({
        ...
        providers: [
           HeroService,LoggerService
        ],bootstrap: [AppComponent]
      })
      export class AppModule { }

      使用 LoggerService 服务

      import { Component,OnInit } from '@angular/core';
      import { HeroService } from '../hero.service';
      import { LoggerService } from './../logger.service';
      
      @Component({
        selector: 'app-hero',template: `
          <ul>
            <li *ngFor="let hero of heros">
              ID: {{hero.id}} - Name: {{hero.name}}
            </li>
          </ul>
        `
      })
      export class HeroComponent implements OnInit {
        heros: Array<{ id: number; name: string }>;
      
        constructor(private heroService: HeroService,private loggerService: LoggerService) { }
      
        ngOnInit() {
          this.loggerService.log('Fetching heros...');
          this.heros = this.heroService.getHeros();
        }
      }

      以上代码运行后会抛出以下异常信息:

      Uncaught Error: Can't resolve all parameters for LoggerService: (?).

      有的读者,眼睛一亮,可能是你在创建 LoggerService 服务时,忘记使用 @Injectable 装饰器了。哈哈,其实我是故意的,但我加上 @Injectable() 后,还是抛出了以下异常:

      ERROR Error: No provider for Boolean!

      为什么会出现上面的异常信息呢?我们再看一下前面创建的 LoggerService 服务:

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

      在 Angular 中我们通过构造注入的方式注入依赖对象, private enable: boolean 这种方式表示我们要注入 Type 类型的对象。然后 boolean 是表示基本数据类型,并不是所需的 Type 类型:

      export function isType(v: any): v is Type<any> {
        return typeof v === 'function';
      }

      接下来我们再来看一下最早抛出的异常:

      Uncaught Error: Can't resolve all parameters for LoggerService: (?).

      其实问题的答应也在 LoggerService 类的构造函数中,在创建 LoggerService 对象时,我们需要设置 enable 参数的值。那么如何解决呢? 当然可以使用我们的主角 - FactoryProvider 。具体如下:

      使用 FactoryProvider

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

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

      LoggerService: Fetching heros...

      难道就这样结束了,关于 FactoryProvider 的相关内容先告一段落,下一篇我们将介绍如何使用 FactoryProvider 配置依赖对象。

猜你在找的Angularjs相关文章