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

目錄

閱讀須知

本系列教程的開發環境及開發語言:ide

基礎知識

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 配置依賴對象。

相關文章
相關標籤/搜索