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

时间:2016-07-05 22:43:06

标签: 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;
    }
}

测试组件

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());
    }
}

控制台中的结果

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Id: 0.24242492129168425
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Id: 0.24242492129168425

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

提前致谢

3 个答案:

答案 0 :(得分: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
    ) {}
    ...
}

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
) {}

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

答案 1 :(得分:4)

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

@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());
    }
}

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

答案 2 :(得分:2)

我会创建一个静态方法,在服务中返回新实例,并在组件中只通过DI注入一个。类似的东西:

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

@Injectable()
export class TestService {

    public id: number = Math.random();

    public toString(): string {
        return "Id: " + this.id;
    }
    static init() {
      return new TestService();
    }
}

然后在组件中:

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

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

    constructor(_testFactory: TestService) { 
       this._testService1 = _testFactory.init();
       this._testService2 = _testFactory.init();
    };

    ngOnInit() {
        console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString());
        console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString());
    }
}