DI 模式是否限制了昂贵的对象创建以及不频繁的依赖项使用?

发布于 2024-11-28 07:08:07 字数 1238 浏览 0 评论 0原文

当涉及到典型的构造函数依赖注入时,我很难理解似乎明显的模式问题/限制。出于示例目的,假设我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

音盲 2024-12-05 07:08:07

如果您有很多字段并未被每个成员使用,则意味着该类的内聚力较低。这是一个通用的编程概念 - 构造函数注入只是让它更加明显。这通常是一个很好的指标,表明单一责任原则正在被违反。

如果是这种情况,请重构(例如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.

蓝眼睛不忧郁 2024-12-05 07:08:07

一般来说,对象构建不应该有重大成本或副作用。这是一个一般性的说法,我认为适用于大多数(不是全部)对象,但对于您通过 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.

何其悲哀 2024-12-05 07:08:07

不,您不受所列出的限制的约束。从 .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 supporting Lazy(Of T) the author has on MSDN.

遇到 2024-12-05 07:08:07

你的控制器不是单例吗?这是在 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文