为什么不使用IoC容器来解析实体/业务对象的依赖关系?

问题描述 投票:75回答:2

我理解DI背后的概念,但我只是在学习不同的IoC容器可以做什么。似乎大多数人都主张使用IoC容器来连接无状态服务,但是如何将它们用于实体等有状态对象呢?

无论是对还是错,我通常会用行为填充我的实体,即使这种行为需要外部类。例:

public class Order : IOrder
{

    private string _ShipAddress;
    private IShipQuoter _ShipQuoter;

    public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
    {
        // OrderData comes from a repository and has the data needed 
        // to construct order
        _ShipAddress = OrderData.ShipAddress;  // etc.
        _ShipQuoter = ShipQuoter;

    }

    private decimal GetShippingRate()
    {
        return _ShipQuoter.GetRate(this);
    }
}

如您所见,依赖项是Constructor Injected。现在提出几个问题。

  1. 让您的实体依赖于诸如ShipQuoter之类的外部类别被认为是不好的做法吗?如果我正确理解定义,消除这些依赖性似乎会导致我陷入贫血领域。
  2. 使用IoC容器来解决这些依赖关系并在需要时构建实体是不好的做法吗?是否有可能做到这一点?

感谢您的任何见解。

dependency-injection inversion-of-control castle-windsor ioc-container entities
2个回答
86
投票

第一个问题是最难回答的问题。让实体依赖外部课程是不好的做法吗?这当然不是最常见的事情。

例如,如果您将Repository注入实体,则实际上有Active Record pattern的实现。有些人喜欢这种模式,因为它提供了方便,而其他人(像我一样)认为它是代码气味或反模式,因为它违反了Single Responsibility Principle(SRP)。

您可以争辩说,将其他依赖项注入实体会使您处于同一方向(远离SRP)。另一方面,你肯定是正确的,如果你不这样做,拉动朝向Anemic Domain Model

很长一段时间我一直在努力解决所有这一切,直到我遇到Greg Young(被遗弃的)paper on DDDD,他解释了为什么陈规定型的n层/ n层架构将永远是CRUDy(因此相当贫乏)。

将我们的重点转移到将对象建模为命令和事件而不是名词似乎使我们能够构建适当的面向对象的域模型。

第二个问题更容易回答。你可以随时使用Abstract Factory to create instances at run-time。使用Castle Windsor,您甚至可以使用Typed Factory Facility,从而减轻您手动实施工厂的负担。


1
投票

我知道这是一个老帖子,但想补充一下。即使您在ctor中传入抽象存储库,域实体也不应该自行保留。我建议这个的原因不仅仅是它违反了SRP,它也违背了DDD的聚合。让我解释一下,DDD适用于具有固有深度图的复杂应用程序,因此,我们使用聚合或复合根来持续改变潜在的“子”,所以当我们将持久性注入个别孩子时,我们违反了孩子们对应该是生命周期或聚合的“负责”的复合或聚合根。当然,复合根或聚合也不会持久化它自己的图形。另一个是注入DDD对象的依赖关系是注入域对象实际上没有状态,直到发生某些其他事件来水合其状态。代码的任何消费者将被迫首先初始化或设置域对象,然后才能调用违反封装的业务行为。

© www.soinside.com 2019 - 2024. All rights reserved.