使用同一服务的多个实例
Using multiple instances of the same service
我有这样的服务:
@Injectable()
export class EditorService { ... }
我有一个组件,像这样:
@Component({
...
template: `<child-component></child-component>`,
providers: [EditorService],
...
})
export class SomeComponent {
constructor(
private _appleEditorService: EditorService,
private _pearEditorService: EditorService) {}
}
您可能已经注意到,此组件有一个子组件:
@Component({
...
selector: 'child-component',
...
})
export class ChildComponent {
constructor(
private _appleEditorService: EditorService,
private _pearEditorService: EditorService) {}
}
如您所见,我想要 EditorService
的两个实例:一个用于编辑苹果,一个用于编辑梨。但是,上面的代码不会起作用,因为 Angular 无法知道 EditorService
的哪个实例是哪个实例,因为它们的变量名是私有的。 ChildComponent
中的 _pearEditorService
可能指的是与 SomeComponent
中的 _appleEditorService
相同的实例。
问题:那我可以使用同一个Angular2服务两次吗?
编辑: 我的问题是是否可以使用相同的 class。我知道有一些解决方法,可以为服务的每个实例实际创建一个单独的 class,甚至可以通过继承用很少的代码来做到这一点。我只是想知道如果没有它是否可以完成。
也许重新考虑你的设计
我认为您可能需要重新考虑您的设计。让两个变量指向完全相同的 EditorService 有什么意义?如果他们共享相同的实现。
继承解决方案
解决这个问题的方法可能是使用继承。我没有看到你们的服务,所以我不确定他们做了什么,但是从这段代码我假设 "apple" 功能和 "pear" 功能实际上是不同的。那么这表明您可能有一些设计问题,并且您的 EditorService 可能做得太多了。也许您可以将对 Apples 和 Pears 都相似的代码移动到名为 EditorService
的服务,然后让两个 类 扩展它。一个 AppleEditorService
和一个 PearEditorService
。
使用一般的水果服务
只是想多谈谈为什么我认为您可能需要重新考虑您的设计。让我们假设 appels 和 pears 实际上具有相同的功能。所以 EditorService
做同样的事情。您希望一个变量用于 'Apples',另一个变量用于 'Pears'。如果我看到该代码(假设其他人在您的团队中工作),我会注意到两个变量都指向同一个服务。 (服务是单例),我很想删除它并制作类似 fruitService : EditorService
之类的东西。
不管怎样,你的问题让我觉得设计应该改变。您不需要该服务的两个实例,服务是单例的,尽管您可以找到解决方法,但我认为这并不是您问题的真正解决方案。
但是正如我之前提到的。想想你的设计。你真的需要两个子服务,还是可以用不同的方式解决?你可以让苹果和梨只是水果的子类吗?您可以只使用一个变量 'fruitService' 而不是同时使用两个 apples/pears 吗?当你想在将来存储 "Strawberries" 时会发生什么?让一堆变量引用相同的服务(因为它们做同样的事情)但具有不同的变量名称不是一个好主意。想象一下在代码中看到这个
appleService = EditorService;
pearService = EditorService;
starwberryService = EditorService;
lemonService = EditorService;
...
guavaService = EditorService;
这不是说明代码有问题吗?我可以想象(此时您没有提供代码)您存储了一个 fruitInstances 数组。但是也许 fruitService 可以工作,然后存储 fruitService.store(Apple a) 并将其放入 'fruit' 的数组中。使用 'filter' 从数组中获取正确的水果应该不会太难。
^ 这是刚刚写的,没有更多的代码可以继续。如果您编辑您的问题,有些事情可能不再成立。
Angular DI 为每个提供者维护一个实例。在您的情况下,如果您有两个具有相同类型的构造函数参数,它们将解析为相同的实例。
你可以做的是提供一个工厂函数(不同于简单的 useFactory
提供者事件,尽管它也使用它)
(示例复制自 )
{ provide: EditorService, useFactory:
(dep1, dep2) => {
return (x) => {
new EditorService(x, dep1, dep2);
}
}, deps: [Dep1, Dep2]
})
....
constructor(@Inject(EditorService) editorServiceFactory: any) {
let editorService1 = editorServiceFactory(1);
let editorService2 = editorServiceFactory(2);
}
如果您有固定数量的实例,这应该有效:
{ provide: 'instance1', useClass: EditorService },
{ provide: 'instance2', useClass: EditorService },
export class SomeComponent {
constructor(
@Inject('instance1') private _appleEditorService: EditorService,
@Inject('instance2') private _pearEditorService: EditorService) {}
}
不太理想,但如果您为每个组件创建一个模块,然后在每个模块上导入您的服务,您将拥有同一服务的 2 个实例(每个模块一个)。
在服务中使用一个对象来存储 X 个实例怎么样...
export class Test {
private vars: any;
constructor() {
vars = {};
}
createInstance(var: any) {
this.vars[var] = var;
}
doSomething(var: any, options): void {
this.vars[var] = someChangeToVar;
}
doSomethingElse(var: any): void {
this.vars[var] = someOtherChangeToVar;
}
get var(var: any): any {
return this.vars[var];
}
}
你调用它的第一个参数是实例的名称...
export class SomeComponent {
constructor(private test: Test) {
// create instance
this.test.createInstance('myInstance');
// do something to it
this.test.doSomething('myInstance', 'some input here');
// get it back
const result = this.test.get('myInstance');
console.log(result);
}
...
}
我有这样的服务:
@Injectable()
export class EditorService { ... }
我有一个组件,像这样:
@Component({
...
template: `<child-component></child-component>`,
providers: [EditorService],
...
})
export class SomeComponent {
constructor(
private _appleEditorService: EditorService,
private _pearEditorService: EditorService) {}
}
您可能已经注意到,此组件有一个子组件:
@Component({
...
selector: 'child-component',
...
})
export class ChildComponent {
constructor(
private _appleEditorService: EditorService,
private _pearEditorService: EditorService) {}
}
如您所见,我想要 EditorService
的两个实例:一个用于编辑苹果,一个用于编辑梨。但是,上面的代码不会起作用,因为 Angular 无法知道 EditorService
的哪个实例是哪个实例,因为它们的变量名是私有的。 ChildComponent
中的 _pearEditorService
可能指的是与 SomeComponent
中的 _appleEditorService
相同的实例。
问题:那我可以使用同一个Angular2服务两次吗?
编辑: 我的问题是是否可以使用相同的 class。我知道有一些解决方法,可以为服务的每个实例实际创建一个单独的 class,甚至可以通过继承用很少的代码来做到这一点。我只是想知道如果没有它是否可以完成。
也许重新考虑你的设计
我认为您可能需要重新考虑您的设计。让两个变量指向完全相同的 EditorService 有什么意义?如果他们共享相同的实现。
继承解决方案
解决这个问题的方法可能是使用继承。我没有看到你们的服务,所以我不确定他们做了什么,但是从这段代码我假设 "apple" 功能和 "pear" 功能实际上是不同的。那么这表明您可能有一些设计问题,并且您的 EditorService 可能做得太多了。也许您可以将对 Apples 和 Pears 都相似的代码移动到名为 EditorService
的服务,然后让两个 类 扩展它。一个 AppleEditorService
和一个 PearEditorService
。
使用一般的水果服务
只是想多谈谈为什么我认为您可能需要重新考虑您的设计。让我们假设 appels 和 pears 实际上具有相同的功能。所以 EditorService
做同样的事情。您希望一个变量用于 'Apples',另一个变量用于 'Pears'。如果我看到该代码(假设其他人在您的团队中工作),我会注意到两个变量都指向同一个服务。 (服务是单例),我很想删除它并制作类似 fruitService : EditorService
之类的东西。
不管怎样,你的问题让我觉得设计应该改变。您不需要该服务的两个实例,服务是单例的,尽管您可以找到解决方法,但我认为这并不是您问题的真正解决方案。
但是正如我之前提到的。想想你的设计。你真的需要两个子服务,还是可以用不同的方式解决?你可以让苹果和梨只是水果的子类吗?您可以只使用一个变量 'fruitService' 而不是同时使用两个 apples/pears 吗?当你想在将来存储 "Strawberries" 时会发生什么?让一堆变量引用相同的服务(因为它们做同样的事情)但具有不同的变量名称不是一个好主意。想象一下在代码中看到这个
appleService = EditorService;
pearService = EditorService;
starwberryService = EditorService;
lemonService = EditorService;
...
guavaService = EditorService;
这不是说明代码有问题吗?我可以想象(此时您没有提供代码)您存储了一个 fruitInstances 数组。但是也许 fruitService 可以工作,然后存储 fruitService.store(Apple a) 并将其放入 'fruit' 的数组中。使用 'filter' 从数组中获取正确的水果应该不会太难。
^ 这是刚刚写的,没有更多的代码可以继续。如果您编辑您的问题,有些事情可能不再成立。
Angular DI 为每个提供者维护一个实例。在您的情况下,如果您有两个具有相同类型的构造函数参数,它们将解析为相同的实例。
你可以做的是提供一个工厂函数(不同于简单的 useFactory
提供者事件,尽管它也使用它)
(示例复制自
{ provide: EditorService, useFactory:
(dep1, dep2) => {
return (x) => {
new EditorService(x, dep1, dep2);
}
}, deps: [Dep1, Dep2]
})
....
constructor(@Inject(EditorService) editorServiceFactory: any) {
let editorService1 = editorServiceFactory(1);
let editorService2 = editorServiceFactory(2);
}
如果您有固定数量的实例,这应该有效:
{ provide: 'instance1', useClass: EditorService },
{ provide: 'instance2', useClass: EditorService },
export class SomeComponent {
constructor(
@Inject('instance1') private _appleEditorService: EditorService,
@Inject('instance2') private _pearEditorService: EditorService) {}
}
不太理想,但如果您为每个组件创建一个模块,然后在每个模块上导入您的服务,您将拥有同一服务的 2 个实例(每个模块一个)。
在服务中使用一个对象来存储 X 个实例怎么样...
export class Test {
private vars: any;
constructor() {
vars = {};
}
createInstance(var: any) {
this.vars[var] = var;
}
doSomething(var: any, options): void {
this.vars[var] = someChangeToVar;
}
doSomethingElse(var: any): void {
this.vars[var] = someOtherChangeToVar;
}
get var(var: any): any {
return this.vars[var];
}
}
你调用它的第一个参数是实例的名称...
export class SomeComponent {
constructor(private test: Test) {
// create instance
this.test.createInstance('myInstance');
// do something to it
this.test.doSomething('myInstance', 'some input here');
// get it back
const result = this.test.get('myInstance');
console.log(result);
}
...
}