贫血域模型和域服务注入


19

所述贫血域模型被描述为由Martin Fowler在领域驱动设计的反模式。为了在域模型上具有业务逻辑,通常使用域服务。但是Vaughn Vernon认为将域服务注入域模型是有害的(请参阅“实施域驱动设计,第387页”)。

我认为这些意见是矛盾的,这是真的吗?如何兼顾这两点?

注入域服务贫血域模型和普通域服务相比真的富域模型吗?


4
我绝不是专家,但是我认为进入域服务和域实体的逻辑类型是根本不同的。进入实体的逻辑是使对象保持正确状态所需的逻辑。这涉及验证和转换逻辑。另一方面,域服务用于更高级别的逻辑。因此,例如,域服务将以复杂的方式对涉及多种不同类型实体的业务流程进行建模。
MetaFight 2015年

2
@MetaFight:即使业务流程以复杂的方式影响多个实体,您也可以在没有良好的“聚合根”域模型的情况下在没有服务的情况下实现此目标,即,该域模型本身可以访问所有受影响的实体作为属性或字段。
Greg Burghardt

这是有道理的:)
MetaFight 2015年

Answers:


16

贫血模型只是一个数据容器。它不包含行为。(在功能范例中,这实际上可能是一件好事。)贫血模型的反面不是注入了全部域服务的模型。您要描述两个极端-都不好。

如果您有贫血模型,那么您不会完全接受OOP提供的功能。如果您开始向这些模型中注入服务,则可能会注入不属于这些模型的关注点。要么那个模型比您想象的更贫乏。除了提供某些必需但缺少的服务之外,您为什么还需要该服务?(缺少可能意味着贫血。)

避免两个“讲”都会导致更坚固的设计。您在模型中需要服务吗?也许应该将其移至模型。如果没有,也许您应该重新考虑您的担忧。模型的行为应模型内部起作用。它应该主要(如果不是唯一的话)与成员关注。但要记住,仍然会有事情,工作模型。例如,模型不应该打开TCP连接或监听UI事件,即使它们以某种方式参与其中。那是其他人的责任,并且永远都不属于模型内部


7
我要记住的一个很好的区别是,您的域模型实现了业务逻辑,而域服务则在域模型上执行了业务逻辑。区别在于谁在呼唤谁。服务可以调用域模型方法。如果域模型正在调用Service方法,那么您已经将模式翻转了过来。
格雷格·伯格哈特

7

这并不矛盾。两个支持者都希望您将实际代码放入域对象本身。

即。

public class Order
{
    private string status = "not bought";
    public void Buy()
    {
        this.status = "bought";
    }
}

与ADM

public class Order
{
    public string Status = "not bought";
}

public class BuyingService
{
    public Order Buy(Order order)
    {
         Order o = new Order();
         o.status = "bought";
         return o;
    }
}

与注入服务

public class Order
{
    public Order(IBuyingService bs)
    {
        _bs = bs;
    }
    private IbuyingService _bs;
    private string status = "not bought";
    public void Buy()
    {
        this.status = _bs.Buy();
    }
}

public class BuyingService : IBuyingService
{
    public string Buy()
    {
         return = "bought";
    }
}

坦白地说,每种方法都有其优点和缺点。您选择的一个很大程度上取决于个人喜好

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.