2017-08-01 104 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); 
} 
相关问题