目錄
- Angular 4 依賴注入教程之一 依賴注入簡介
- Angular 4 依賴注入教程之二 組件服務注入
- Angular 4 依賴注入教程之三 ClassProvider的使用
- Angular 4 依賴注入教程之四 FactoryProvider的使用
- Angular 4 依賴注入教程之五 FactoryProvider配置依賴對象
- Angular 4 依賴注入教程之六 Injectable 裝飾器
- Angular 4 依賴注入教程之七 ValueProvider的使用
- Angular 4 依賴注入教程之八 InjectToken的使用
閱讀須知
本系列教程的開發環境及開發語言:
基礎知識
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
屬性用來聲明依賴對象列表。