为什么不使用IoC容器来parsing实体/业务对象的依赖关系?
我了解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); } }
正如你所看到的,依赖关系是注入构造函数。 现在有几个问题。
-
让您的实体依赖外部类如ShipQuoter被认为是不好的做法? 如果我正确地理解了定义,消除这些依赖似乎导致我走向一个贫血的领域。
-
使用IoC容器来解决这些依赖关系并在需要时构造一个实体是不好的做法吗? 可以这样做吗?
感谢您的任何见解。
第一个问题是最难回答的问题。 实体依赖于外部类是不好的做法? 这当然不是最常见的事情。
例如,如果您向实体中注入了一个Repository,那么您将有效地实现Active Record模式 。 有些人为了方便起见而喜欢这种模式,而另外一些人(比如我)认为这是一种代码异味或反模式,因为它违反了单一职责原则 (SRP)。
你可以争辩说,注入其他依赖到实体会拉你在同一个方向(远离SRP)。 另一方面,你肯定是正确的,如果你不这样做的话,拉向一个贫血领域模型 。
我一直努力争取了很长时间,直到我遇到格雷格·扬(放弃)[关于DDDD的论文] [4],他解释了为什么定型的n层/ n层架构总是CRUDy (因此贫血)。
将我们的焦点转移到将域对象作为命令和事件而不是名词来build模似乎使我们能够build立一个适当的面向对象的领域模型。
第二个问题更容易回答。 您始终可以使用抽象工厂在运行时创build实例 。 与温莎城堡,你甚至可以使用types的工厂设施,减轻你手动实施工厂的负担。
我知道这是一个旧的职位,但想补充。 即使您通过ctor中的抽象存储库,域实体也不应该自行保留。 我提出这个build议的原因不仅在于它违反了SRP,而且也违背了DDD的聚合。 让我解释一下,DDD适合具有内在深度图的复杂应用程序,因此,我们使用聚合或复合根来持久化底层的“子”,所以当我们注入持久化到个别的孩子,我们违反了孩子们的关系应该是生命周期或聚合的“主pipe”的复合或聚合根。 当然,复合根或集合也不会保留它自己的graphics。 另一个是注入DDD对象的依赖关系是注入的域对象有效地没有状态,直到其他事件发生,以保持其状态。 任何代码的使用者在调用违反封装的业务行为之前都将被迫首先初始化或设置域对象。