服务定位器比依赖注入更容易使用?
我正在开发的应用程序依赖 Autofac 作为 DI 容器,让我决定使用它的原因之一是委托工厂功能(请参阅 here)
这适用于我需要多次重新创建相同元素的所有情况,就像某些报告的情况一样和相关屏幕。一些报告(甚至是相同类型的报告)是同时执行的,但它们仅通过用户定义的参数进行更改,因此(我认为)注入工厂以创建实例、传递自由参数并将其余部分留给应用。
问题在于,每个报告都由数量可变的子报告(任务)组成,并且每个任务都实现一个 ITask 接口。每个报告最多可以有 50 个不同的任务可供使用,每个任务都封装了精确的业务操作。我的一种选择是注入委托工厂并在需要时创建它们。
这些任务必须由工厂动态生成,例如:
var myTaskA = _taskFactoryConcreteTaskA();
var myTaskB = _taskFactoryConcreteTaskB();
var myTaskC = _taskFactoryConcreteTaskC();
...
var myTaskZZ = = _taskFactoryConcreteTaskZZ();
需要大量手动接线(委托、构造函数、支持字段等),而类似的
var myTaskA = _taskFactory.Create<ConcreteTaskA>();
var myTaskB = _taskFactory.Create<ConcreteTaskB>();
var myTaskC = _taskFactory.Create<ConcreteTaskC>();
...
var myTaskZZ = _taskFactory.Create<ConcreteTaskZZ>();
工作量会少得多,特别是如果 _taskFactory 包装容器,如 这篇文章,但这基本上意味着我正在使用服务定位器创建我的任务。
我还有哪些其他选择可能适合解决此问题?
(注意:我很有可能完全偏离了轨道,我必须阅读更多有关 DI 的内容,在这种情况下,任何贡献都将更加重要)
The application I am working on is relying on Autofac as DI container and one of the reasons that made me decide to use it, among others, was the delegate factory feature (see here)
This works fine for all cases where I need to recreate the same elements several times as is the case of some reports and related screens. Some reports (even those of the same type) are executed concurrently but they change only by their user-defined parameters so it makes sense (I think) to inject factories in order to create instances, passing the free parameters and leave the rest to the application.
The problem comes with the fact that each report is made of a variable number of sub reports (tasks) and each task implements an ITask interface. Each report may have up to 50 different tasks to use and each task encapsulates a precise business operation. One option I have is to inject delegate factories for and create them when needed.
These tasks have to be dynamically generated by factories and something like:
var myTaskA = _taskFactoryConcreteTaskA();
var myTaskB = _taskFactoryConcreteTaskB();
var myTaskC = _taskFactoryConcreteTaskC();
...
var myTaskZZ = = _taskFactoryConcreteTaskZZ();
requires a lot of manual wiring (delegates, constructor, backing fields etc) while something like
var myTaskA = _taskFactory.Create<ConcreteTaskA>();
var myTaskB = _taskFactory.Create<ConcreteTaskB>();
var myTaskC = _taskFactory.Create<ConcreteTaskC>();
...
var myTaskZZ = _taskFactory.Create<ConcreteTaskZZ>();
would be incredibly less work especially if the _taskFactory wraps the container as shown in this other post, but also it would basically mean I am using a service locator to create my tasks.
What other options do I have that may be suitable to solve this?
(NOTE: there is a good chance I am completely off track and that I have to read a lot more about DI, in which case any contribution would be even more important)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于问题中指出的工厂不接受任何参数,因此使用工厂有一种泄漏抽象的味道。正如 Nicholas Blumhardt 在他的回答中指出的那样,更好的方法可能是简单地将每项任务注入消费者。
在这种情况下,由于所有任务都实现相同的接口,因此您可以组合它们,而不是注入最多 50 个不同的
ITask
实例:或者,您可以组合
ITask
序列> 变成 Composite,这实际上是我首选的解决方案:这将简化消费者并转变事实有一个实施细节中需要执行多个任务:
Since the factories indicated in the question don't take any arguments, using a factory smells of a Leaky Abstraction. As Nicholas Blumhardt points out in his answer, a better approach might be to simply inject each task into the consumer.
In this case, since all the tasks implement the same interface, instead of injecting up to 50 different
ITask
instances, you can compose them:Alternatively, you can compose the sequence of
ITasks
into a Composite, which is actually my preferred solution:This would simplify the consumer and turn the fact that there are more than one task to be performed into an implementation detail:
一种值得研究的方法是将问题分解为使用一组相关任务的“工作单元”:
然后,您对工厂的使用将趋向于
someWorkFactory().DoSomething()
,可能用于几种不同种类的“东西”。一个类对工厂或其他任何东西有大量的依赖关系,通常表明有更小、更集中的类等待被发现来分解工作。
希望这有帮助。
One approach worth investigating is to break the problem into'units of work' that use a set of related tasks:
Then, your use of factories would come down towards
someWorkFactory().DoSomething()
, possibly for a few different kinds of 'something'.A class having a large number of dependencies, on factories or anything else, usually points to there being smaller, more focused classes waiting to be discovered to break up the work.
Hope this helps.