我在 .net 核心 C# 应用程序中有以下方案:
Service A -> Subject<Foo> -> Service B
Service C -> Subject<Foo> -> Service D
Subject<Foo>
的两个实例具有不同的语义,因此它们需要是不同的实例。让我们假设第一个主题提供"很棒"Foo
,第二个主题提供"很棒"Foo
。
Subject<Foo>
现在,我想使用 dotnet core 附带的依赖项注入将Subject<Foo>
的两个实例添加到容器中,以便可以使用它们所依赖的主题构造所有服务(A 和 B 依赖于第一个实例, 第二个是 C 和 D)。
我的第一个想法是创建派生接口IFooFirstSubject : ISubject<Foo>
和IFooSecondSubject : ISubject<Foo>
:
services.AddSingleton<IFooFirstSubject>( HOW TO GET A FooFirstSubject Instance?! );
services.AddSingleton<IFooSecondSubject>( HOW TO GET A FooSecondSubject Instance?! );
但是,现在我需要一个具体的 Subject 实现来实现IFooFirstSubject
接口。一个想法是Subject
子类并实现标记接口Subject
但它是一个密封类。我目前看到三种方法,我对这两种方法都不满意:
1)与其使A和B依赖于主题,不如创建一个SubjectRegister
具体的类,A,B,C,D可以从中查询他们想要的主题,就像subjectRegister.FooFirstSubject
一样。将寄存器放在两者之间对我来说似乎是一种气味。
2)使用适配器模式解决密封类问题。 然后,FooFirstSubject
可以实现IFooFirstSubject
并使用(而不是派生自)Subject
。如果我的服务之间有很多主题,这似乎是一大堆工作。
3) 可能有一种方法可以使用反射添加标记接口。这也感觉我正在做一些不应该做的事情。
从某种意义上说:有没有另一种方法(也许我什至在这里使用了错误的类Subject
?)来实现我想要做的事情?
编辑:我创建了一个冗长的解释,说明我在这里为什么要完成的原因和内容(由于许多评论,谢谢他们!):https://gist.github.com/anonymous/e933846c2c8e213128a49a2a6f8f7154
问题是,依赖注入适用于类型,如果有两个完全相同类型的实例,那么 DI 无法消除这两者之间的歧义。至少除非你使用在Microsoft.Extensions.DependencyInjection中不可用的键控依赖项,这可能是设计不好的标志。
你应该考虑一下你是否真的需要在这里单独的科目。我理解您的情况的方式(以及通过更具体的基于推文的示例),您正在使用主题发布有关该Foo
对象的事件。您需要两个不同的主题,因为您希望不同的组件订阅两个不同的事件。
因此,您实际上具有不同的事件类型,这表明您应该具有有关事件的主题,而不是有关事件目标的主题。所以你会有一个Subject<AwesomeFooDelivered>
和一个Subject<GreatFooDelivered>
.然后,这两个事件都将具有对实际Foo
的引用,但这样组件可以订阅实际事件,而不是发生某些事情的对象。
使用您的SO Q/A问题示例,这将使这Subject<QuestionPosted>
和Subject<QuestionUpvoted>
;而使用您的推文示例,您将拥有Subject<TweetReceived>
和Subject<HashtagDiscovered>
。
通过让事件的主题,您可以轻松地让多个组件订阅同一事件主题,并让多个组件独立订阅事件。因此,这将允许您真正解耦。
由于主题现在属于不同的类型,因此将它们注册为依赖项也不会有问题,并且依赖于它们的组件将再次清楚它们实际依赖的内容,从而使您的架构更加清晰。
只需注册具体实现的实例即可。 接口很好,但不是绝对必要的。
services.AddSingleton(new Subject<Foo>());