【问题标题】:Inject all Services that implement some Interface注入所有实现某个接口的服务
【发布时间】:2016-03-10 12:29:59
【问题描述】:

简单场景:

我有多个实现通用接口的服务。所有这些服务都在bootstrap 方法中注册。

现在我想要另一个服务,它注入所有实现公共接口的注册服务。

export interface MyInterface {
    foo(): void;
}

export class Service1 implements MyInterface {
    foo() { console.out("bar"); }
}

export class Service2 implements MyInterface {
    foo() { console.out("baz"); }
}

export class CollectorService {
    constructor(services:MyInterface[]) {
        services.forEach(s => s.foo());
    }
}

这有可能吗?

【问题讨论】:

    标签: angular angular2-services


    【解决方案1】:

    您需要像这样注册您的服务提供商:

    boostrap(AppComponent, [
      provide(MyInterface, { useClass: Service1, multi:true });
      provide(MyInterface, { useClass: Service2, multi:true });
    ]);
    

    这仅适用于没有接口的类,因为接口在运行时不存在。

    要使其与接口一起使用,您需要对其进行调整:

    bootstrap(AppComponent, [
      provide('MyInterface', { useClass: Service1, multi:true }),
      provide('MyInterface', { useClass: Service2, multi:true }),
      CollectorService
    ]);
    

    并以这种方式注入:

    @Injectable()
    export class CollectorService {
      constructor(@Inject('MyInterface') services:MyInterface[]) {
        services.forEach(s => s.foo());
      }
    }
    

    请参阅此 plunkr 了解更多详情:https://plnkr.co/edit/HSqOEN?p=preview

    查看此链接了解更多详情:

    【讨论】:

    【解决方案2】:

    因为接口在运行时不可用(仅用于静态检查)接口不能用作 DI 的令牌。

    改用令牌:

    (已弃用) https://angular.io/api/core/OpaqueToken

    var myInterfaceToken = new OpaqueToken('MyInterface');
    

    https://angular.io/api/core/InjectionToken

    var myInterfaceToken new InjectionToken<MyInterface>('MyInterface');
    
    // import `myInterfaceToken` to make it available in this file
    
    @NgModule({
      providers: [ 
        { provide: myInterfaceToken, useClass: Service1, multi:true },
        { provide: myInterfaceToken, useClass: Service2, multi:true },
      ],
      boostrap: [AppComponent],
    )
    class AppComponent {}
    
    // import `myInterfaceToken` to make it available in this file
    
    export class CollectorService {
        constructor(@Inject(myInterfaceToken) services:MyInterface[]) {
            services.forEach(s => s.foo());
        }
    }
    

    【讨论】:

    • 使用 OpaqueToken 是提供接口实现的推荐方式。
    • 使用 InjectionToken 而不是 OpaqueToken,因为最后一个自角度 4 以来已被弃用。angular.io/api/core/InjectionToken
    • 结合使用这个答案和Angular2 How can I Inject all interface implementation to service as list?,我设法让事情顺利进行。谢谢!对此答案:提供程序语法已更改为:{ provide: MY_CLASS_INJECTION_TOKEN, useClass: MY_CLASS, multi: true } 并添加到启动模块(至少我将其添加到启动模块...)
    • @MartinJH 很高兴听到!感谢您的提示。这是一个相当古老的答案。我更新了。
    • 反应迅速。感谢您的努力!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 2018-08-30
    • 2011-12-05
    • 1970-01-01
    • 2015-05-20
    相关资源
    最近更新 更多