2017-08-01 48 views
1

我試圖用兩種方法明確地創建依賴關係。兩者幾乎都是相同的,但我有點混淆在正常噴油器上使用反射式噴油器的優點以及推薦的方法是哪一種?反射式噴油器和噴油器之間的差異

使用注射器

import { Injector } from '@angular/core'; 
constructor(private injector: Injector) { 
    this.myService = this.injector.get(MyService); 
    } 

使用反光注射器

import { ReflectiveInjector } from '@angular/core'; 
constructor() { 

     var injector= ReflectiveInjector.resolveAndCreate([MyService]); 
     let myservice=injector.get(MyService); 
    } 
+2

'Injector'是一個容器,不能創建新的供應商。 'ReflectiveInjector'具有工廠方法,允許您在運行時定義新的提供者(即創建新的子注入器)。 – cgTag

+0

@ThinkingMedia兒童注射器意味着孩子的依賴? – JEMI

+0

@ThinkingMedia我有一個沒有孩子依賴的服務。我想明確地創建它的一個實例。哪一個是推薦的方法? – JEMI

回答

4

的噴射器是與供應商/服務的容器。它實現了一個方法get並返回服務的一個實例。讓我們實現JS僞噴油器的最基本的版本:

class ReflectiveInjector { 
    providers = []; 

    static resolveAndCreate(providers) { 
    providers.forEach((provider)=>{ 
     providers.push({token: provider.provide, instance: new provider.useClass}) 
    }); 
)} 

    get(dep) { 
    return providers.find((provider)=>{ return provider.token === token }); 
    } 
} 

現在,我們需要創建注入的情況下才可以使用它。當我們創建它時,我們定義提供者:

const existingInjector = ReflectiveInjector.resolveAndCreate([{provide: A, useClass: A }]); 
const AInstance = existingInjector.get(A); 

因此,您看到要使用注射器,必須先創建注射器。它沒有任何特定的方法允許在創建完成後添加提供程序,因此我們無法添加任何新的提供程序。

您注入組件構造函數的注入器已由Angular創建。您無法添加任何內容,只能查詢已定義的提供者。如果您需要提供B課程,則不能使用現有注射器來完成。你需要一個新的。這就是ReflectiveInjector類的用途。它允許您通過創建注入器的新實例並註冊新的提供者來添加新的提供者。最好的部分是它也可以設置一個噴油器鏈。

讓我們有點修改resolveAndCreateget方法來允許鏈接注射器:

class ReflectiveInjector { 
    providers = []; 
    parent; 

    static resolveAndCreate(providers, parent) { 
     this.parent = parent; 
    ... 
    } 

    get(dep) { 
     let found = providers.find((provider)=>{ return provider.token === token }); 
     if (!found && parent) { 
      found = parent.get(dep); 
     } 

     return found; 
    } 

所以現在只有左邊是使用它:

// passing existingInjector as a parent 
const childInjector = ReflectiveInjector.resolveAndCreate([{provide: B, useClass: B }], i); 
const AInstance = childInjector.get(A); 
const BInstance = childInjector.get(B); 

現在,假如有人可能希望得到訪問我們的existingInjector。我們需要一個令牌來獲得這個現有的注射器。讓我們來定義此令牌是這樣的:

abstract class Injector {} 

,讓我們寫一個函數,將讓現有的注射器:

function resolveDependency(token) { 
    if (token === Injector) { 
     return existingInjector; 
    } 
} 

當執行元件的構造,現在假設角,使用令牌你指定獲取依賴關係並將它們傳遞給resolveDependency函數。所以,你這樣寫:

// the Injector here is a reference to our abstract Injector class and simply used as a token 
MyComp { 
    constructor(private injector: Injector) { ... } 
} 

這裏的令牌是Injector這是我說的是傳遞到resolveDependency功能並返回現有的注射器。

+0

我認爲第一個類名是Injector not ReflectiveInjector。你可以確認嗎? – JEMI

+0

不,它是ReflectiveInjector,讓我補充一些說明 –

+0

@JEMI,我已經更新了答案 –

1

Angular只會爲每個提供者創建一個實例。因此,如果你想使用Injector作爲工廠,你不能。您必須爲每個需要的對象的新實例創建一個新的注入器。

假設我們有一個名爲ReportsService的服務類,它需要在運行時創建Record對象,但是您希望Record是可注入的。

下面是我們需要創建多個實例的類。

@Injectable() // does not have to be defined in ngModule 
export class Record { 
     // just an example dependency that ReportsService doesn't know about 
     public constructor(http: Http) { 
     } 
} 

這是創建上述類的服務。

@Injectable() // exported via ngModule 
export class RecordsService { 
     // we need injector as parent otherwise Record class will not find Http 
     public constructor(private parent: Injector) { 
     } 

     // factory method 
     public createRecord(): Record { 
      // creates a new injector that knows about Record but extends existing injector 
      let injector = ReflectiveInjector.resolveAndCreate([ 
      {provide: Record, useClass: Record} 
      ], this.parent); 

      // first call, object is created 
      let record = injector.get(Record); 
      // just an example 
      let example = injector.get(Record); 
      // will output true 
      console.log(record === example ? 'true' : 'false'); 

      return record; 
    } 
} 

現在Record的新實例很棒,但是如果每個對象完全相同,那有什麼意義呢?所以我們需要爲Record注入參數。我們將爲字符串值創建一個標記。

export const RECORD_URL = new InjectionToken<string>('record-url'); 

@Injectable() 
export class Record { 
     public constructor(http: Http, @Inject(RECORD_URL) url: string) { 
     } 
} 

現在更新創建功能

public createRecord(url: string): Record { 
    let injector = ReflectiveInjector.resolveAndCreate([ 
     {provide: Record, useClass: Record}, 
     {provide: RECORD_URL, useValue: url 
    ], this.parent); 
    return injector.get(Record); 
}