DI 模式是否限制了昂贵的对象创建以及不频繁的依赖项使用?
当涉及到典型的构造函数依赖注入时,我很难理解似乎明显的模式问题/限制。出于示例目的,假设我有一个 ASP.NET MVC3 控制器,如下所示:
Public Class MyController
Inherits Controller
Private ReadOnly mServiceA As IServiceA
Private ReadOnly mServiceB As IServiceB
Private ReadOnly mServiceC As IServiceC
Public Sub New(serviceA As IServiceA, serviceB As IServiceB, serviceC As IServiceC)
Me.mServiceA = serviceA
Me.mServiceB = serviceB
Me.mServiceC = serviceC
End Sub
Public Function ActionA() As ActionResult
' Do something with Me.mServiceA and Me.mServiceB
End Function
Public Function ActionB() As ActionResult
' Do something with Me.mServiceB and Me.mServiceC
End Function
End Class
我很难克服的问题是 DI 容器被要求实例化所有三个依赖项在任何给定时间,该控制器上的操作方法可能只需要依赖项的子集。
似乎假设对象构造非常便宜,并且对象构造没有副作用,或者所有依赖项都得到一致利用。如果对象构造不便宜或者有副作用怎么办?例如,如果构造IServiceA
涉及打开连接或分配其他重要资源,那么当调用ActionB
时,这将完全浪费时间/资源。
如果这些操作方法使用服务位置模式(或其他类似模式),那么就永远不会有机会不必要地构造将不使用的对象实例,当然使用此模式会带来其他问题,使其没有吸引力。
使用 DI 的规范构造函数注入+接口模式是否基本上将开发人员锁定在某种“限制”中,即依赖项的实现必须很便宜才能实例化,或者必须充分利用实例?我知道所有模式都有其优点和缺点,这只是 DI 的缺点之一吗?我以前从未见过有人提到过它,我对此感到好奇。
I'm having a hard time getting my head around what seems like an obvious pattern problem/limitation when it comes to typical constructor dependency injection. For example purposes, lets say I have an ASP.NET MVC3 controller that looks like:
Public Class MyController
Inherits Controller
Private ReadOnly mServiceA As IServiceA
Private ReadOnly mServiceB As IServiceB
Private ReadOnly mServiceC As IServiceC
Public Sub New(serviceA As IServiceA, serviceB As IServiceB, serviceC As IServiceC)
Me.mServiceA = serviceA
Me.mServiceB = serviceB
Me.mServiceC = serviceC
End Sub
Public Function ActionA() As ActionResult
' Do something with Me.mServiceA and Me.mServiceB
End Function
Public Function ActionB() As ActionResult
' Do something with Me.mServiceB and Me.mServiceC
End Function
End Class
The thing I'm having a hard time getting over is the fact that the DI container was asked to instantiate all three dependencies when at any given time only a subset of the dependencies may be required by the action methods on this controller.
It's seems assumed that object construction is dirt-cheep and there are no side effects from object construction OR all dependencies are consistently utilized. What if object construction wasn't cheep or there were side effects? For example, if constructing IServiceA
involved opening a connection or allocating other significant resources, then that would be completely wasted time/resources when ActionB
is called.
If these action methods used a service location pattern (or other similar pattern), then there would never be the chance to unnecessarily construct an object instance that will go unused, of course using this pattern has other issues attached making it unattractive.
Does using the canonical constructor injection + interfaces pattern of DI basically lock the developer into a "limitation" of sorts that implementations of the dependency must be cheep to instantiate or the instance must be significantly utilized? I know all patterns have their pros and cons, is this just one of DI's cons? I've never seen it mentioned before, which I find curious.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您有很多字段并未被每个成员使用,则意味着该类的内聚力较低。这是一个通用的编程概念 - 构造函数注入只是让它更加明显。这通常是一个很好的指标,表明单一责任原则正在被违反。
如果是这种情况,请重构(例如Facade Services)。
创建对象图时不必担心性能。
当谈到副作用时,(DI) 构造函数应该简单并且没有副作用。
If you have a lot of fields that aren't being used by every member this means that the class' cohesion is low. This is a general programming concept - Constructor Injection just makes it more visible. It's usually a pretty good indicator that the Single Responsibility Principle is being violated.
If that's the case then refactor (e.g. to Facade Services).
You don't have to worry about performance when creating object graphs.
When it comes to side effects, (DI) constructors should be simple and not have side effects.
一般来说,对象构建不应该有重大成本或副作用。这是一个一般性的说法,我认为适用于大多数(不是全部)对象,但对于您通过 DI 注入的服务尤其如此。换句话说,构建服务类会自动进行数据库/服务调用,或者以产生副作用(至少是代码味道)的方式更改系统状态。
关于未使用的实例:无论您是否使用 DI,都很难创建一个能够完美利用依赖类中的实例的系统。我不确定实现这一点是否非常重要,只要您遵守单一责任原则。如果您发现您的类注入了太多服务,或者利用率确实不均匀,这可能表明您的类做得太多,需要分成两个或更多较小的类责任更加集中。
Generally speaking, there should be no major costs or side effects of object construction. This is a general statement that I believe applies to most (not all) objects, but is especially true for services that you would inject via DI. In other words, constructing a service class automatically makes a database/service call, or changes the state of your system in a way that would have side effects is (at least) a code smell.
Regarding instances that go unused: it's hard to create a system that has perfect utilization of instances within dependent classes, regardless of whether you use DI or not. I'm not sure achieving this is very important, as long as you are adhering to the Single Responsibility Principle. If you find that your class has too many services injected, or that utilization is really uneven, it might be a sign that your class is doing too much and needs to be split into two or more smaller classes with more focused responsibilities.
不,您不受所列出的限制的约束。从 .net 4 开始,您的计算机上确实有 Lazy(Of T)处置,这将允许您将依赖项的实例化推迟到需要时。
并不认为对象构造非常便宜,因此一些 DI 容器支持
Lazy(Of T)
开箱即用。虽然 Unity 2.0 通过 支持开箱即用的延迟初始化自动化工厂,有一篇好文章此处支持Lazy 的扩展(T)
作者在 MSDN。No you are not tied to the limitations you have listed. As of .net 4 you do have Lazy(Of T) at your disposal, which will allow you to defer instantiation of your dependencies until required.
It is not assumed that object construction is dirt-cheap and consequently some DI containers support
Lazy(Of T)
out of the box. Whilst Unity 2.0 supports lazy initialization out of the box through automatic factories, there is a good article here on an extension supportingLazy(Of T)
the author has on MSDN.你的控制器不是单例吗?这是在 Java 中执行此操作的正常方法。仅创建了一个实例。如果操作的角色如此不同,您还可以将控制器拆分为多个控制器。
Isn't your controller a singleton though? That is the normal way to do it in Java. There is only one instance created. Also you could split the controller into multiple controllers if the roles of the actions is so distinct.