Angular2 DI - 在同一构造函数中初始化多个不同的实例

RVP*_*RVP 8 dependency-injection typescript angular

我有一个Angular2 DI问题.假设我有一个TestService,我想在同一个组件中使用此服务的2个不同实例.如果我只是将一个提供程序添加到组件中,并将2个实例添加到构造函数中,那么我最终会使用相同的服务实例.例如:

TestService的

import {Injectable} from "@angular/core";

@Injectable()
export class TestService {

    public id: number = Math.random();

    public toString(): string {
        return "Id: " + this.id;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试组件

import {Component, Input, OnInit} from "@angular/core";
import {TestService} from "../../services/test.service";

@Component({
    providers: [TestService]
})
export class TestComponent implements OnInit {

    constructor(private _testService1: TestService, private _testService2: TestService) { };

    ngOnInit() {
        console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString());
        console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

结果在控制台中

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Id: 0.24242492129168425
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Id: 0.24242492129168425
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我是否有办法使用Angular2的DI机制在同一组件中注入多个不同的服务实例,或者我应该删除这个特定情况的DI并使用手动构造函数手动创建我的实例?

提前致谢

Est*_*ask 10

鉴于实例数量有限,直截了当的方式可能是:

@Component({
    providers: [
        { provide: 'TestService1', useClass: TestService },
        { provide: 'TestService2', useClass: TestService }
    ]
})
export class TestComponent implements OnInit {
    constructor(
        @Inject('TestService1') private _testService1: TestService,
        @Inject('TestService2') private _testService2: TestService
    ) {}
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者OpaqueToken相反避免使用相同的字符串标识符覆盖服务:

export const TestService1 = new OpaqueToken;
export const TestService2 = new OpaqueToken;

...
providers: [
    { provide: TestService1, useClass: TestService },
    { provide: TestService2, useClass: TestService }
]
...
constructor(
    @Inject(TestService1) private _testService1: TestService,
    @Inject(TestService2) private _testService2: TestService
) {}
Run Code Online (Sandbox Code Playgroud)

它不会伤害TestService构造函数中的DI .并且保持可测试性,TestComponent并且可以独立地模拟两个服务实例.

  • 很好的答案.要完成,我会说也应该使用OpaqueToken而不是字符串来避免命名冲突:https://angular.io/docs/ts/latest/api/core/index/OpaqueToken-class.html (2认同)

Gün*_*uer 5

您可以注入一个工厂,每次调用它时都会返回一个新实例:

@NgModule({
   providers: [{
      provide: 'testService', 
      useFactory: (/* TestService deps here like `http`*/) => 
        (/* params */) => new TestService(/* http */), 
      deps: [/* TestService deps here like `Http`*/ ]
    }]
})


@Component(...)
export class TestComponent implements OnInit {

    constructor(@Inject('testService') private _testServiceFactory) { };

    ngOnInit() {
        console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testServiceFactory( /* params */).toString());
        console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testServiceFactory().toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

Plunker 示例 (单击按钮时检查浏览器控制台中的输出)

  • 它只是不做这项工作。如果使用 useFactory 注入,则工厂将仅用于注入 _testServiceFactory 一次。但是这个片段无论如何都不会工作,因为你没有构造函数参数的类型,angular 不知道要注入什么。 (2认同)