使用同一服务的多个实例
Posted
技术标签:
【中文标题】使用同一服务的多个实例【英文标题】:Using multiple instances of the same service 【发布时间】:2016-11-23 18:07:09 【问题描述】:我有一个服务,像这样:
@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
的哪个实例是哪个实例,因为它们的变量名是私有的。 _pearEditorService
in ChildComponent
可能与 _appleEditorService
在 SomeComponent
中引用相同的实例。
问题:否则,我可以两次使用同一个 Angular2 服务吗?
编辑:我的问题是是否可以使用同一个类。我知道有一些解决方法,可以为服务的每个实例创建一个单独的类,甚至可以通过继承使用很少的代码来实现。我只是想知道是否可以不这样做。
【问题讨论】:
【参考方案1】:Angular DI 为每个提供者维护一个实例。在您的情况下,如果您有两个具有相同类型的构造函数参数,它们会解析为同一个实例。
您可以做的是提供一个工厂函数(与简单的useFactory
提供程序事件不同,尽管它也使用它)
(从https://***.com/a/37517575/217408复制的示例)
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)
【讨论】:
^ 这实际上可能是一个可行的解决方法。以前没见过,现在无法测试。会给你投票,因为这是对 OP 的更直接的答案,而不是我的答案:-) 指出问题的其他观点总是一个好主意,也可以投票:-) 我终于明白什么时候我使用注入和一个简单的new()
- 我已经创建了一个plunker,所以我会一直记住它,以防其他人想要:plnkr.co/edit/tsay1qciOkxOS74MOBNo?p=info
我了解linked answer 中的解决方案如何与嵌套在(dep1, dep2)
内的函数(x)
一起工作,但我不明白这里的预期是什么,因为(x)
是@987654333 周围的闭包@。在这个答案中嵌套的函数是否错误?如果这个答案是正确的,那么如果嵌套的 deps 没有被输入,它们如何得到正确的解析?
你是对的。非常感谢您的提示。我混合了嵌套方法的签名。 plnkr.co/edit/Jbrr0vfMxb1sIR2GvVtW?p=preview【参考方案2】:
也许会重新考虑你的设计
我认为你可能不得不重新考虑你的设计。让两个变量指向完全相同的 EditorService 有什么意义?如果他们共享相同的实现。
继承解决方案
对此的解决方案可能是使用继承。我没有看到你的服务,所以我不确定他们做了什么,但从这段代码中我假设“苹果”功能和“梨”功能实际上是不同的。那么这表明您可能有一些设计问题,并且您的 EditorService 可能做得太多。也许您可以将与 Apples 和 Pears 相似的代码移动到名为 EditorService
的服务中,然后让两个类扩展它。一个AppleEditorService
和一个PearEditorService
。
使用通用fruitService
只是想多谈谈我认为您可能需要重新考虑您的设计的原因。让我们假设 appels 和 pears 实际上具有相同的功能。所以EditorService
也一样。您希望一个变量用于“Apples”,一个用于“Pears”。如果我看到该代码(假设其他人在您的团队中工作),并且我注意到两个变量都指向同一个服务。 (服务是单例的),我只是想删除它并制作类似fruitService : EditorService
或类似的东西。
无论哪种方式,您的问题都让我认为应该更改设计。您不想要服务的两个实例,服务是单例的,虽然您可以找到解决方法,但我认为这并不是解决问题的真正方法。
但正如我之前提到的。想想你的设计。你真的需要两个子服务,或者你能用不同的方式解决它吗?你能吃苹果和梨子类水果吗?您可以只使用一个变量“fruitService”而不是两个苹果/梨吗?当您将来也想存储“草莓”时会发生什么?有一堆变量指的是同一个服务(因为它们做同样的事情)但具有不同的变量名称不是一个好主意。想象一下在代码中看到这一点
appleService = EditorService;
pearService = EditorService;
starwberryService = EditorService;
lemonService = EditorService;
...
guavaService = EditorService;
这不是表示代码有些奇怪吗?我可以想象(此时您没有提供代码)您存储了一个水果实例数组。但是也许fruitService 可以工作,然后存储fruitService.store(Apple a) 并将其放入“水果”数组中。使用“过滤器”从阵列中获取正确的水果应该不会太难。
^ 这只是在没有更多代码的情况下编写的。如果您编辑您的问题,有些事情可能不再成立。
【讨论】:
好吧,我可以想到 许多 原因,为什么任何 any 可变类会被实例化多次,即使它是用零参数构造的。这就是实例的重点,如果你改变一个,改变它的状态,你不会改变另一个。继承显然是最快的解决方法,感谢您指出这一点,但我的问题真的是 Angular2 是否可以用同一个类做到这一点。 @Devaro 你在这里使用服务。服务是单例的。我知道您可以获得它们的多个实例 - 在 不同的 类中,但不能在同一个类中。 (范围提供者)。单例总是只有一个实例。我不认为继承在这里是一种解决方法——我认为这只是处理服务的一种正常方式。但是您的服务可能不好,无法从您的代码中推断出来。也许他们没有以 angular2 的最佳方式做事。 嗯好的。没有压倒他们是单身人士的事实。好的,谢谢你的帮助。 这不应该是公认的答案,因为它不能正确回答问题。有关解决方案,请参阅下面的 Gunters 回答【参考方案3】:如何使用服务中的对象来存储 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);
...
【讨论】:
【参考方案4】:不理想,但如果您为每个组件创建一个模块,然后在每个模块上导入您的服务,您将拥有相同服务的 2 个实例(每个模块一个)。
【讨论】:
以上是关于使用同一服务的多个实例的主要内容,如果未能解决你的问题,请参考以下文章