AnemicDomainModel - 需要更简单的解释

时间:2012-01-26 01:24:27

标签: domain-driven-design

我今天阅读了this文章,并试图澄清一些事情。本文是否意味着模型对象应包含业务逻辑? 例如,让我们说有一个Student对象,我们通过Hibernate从数据库中检索它。本文是否说Student对象应该包含业务逻辑,而不仅仅是getter和setter?

2 个答案:

答案 0 :(得分:6)

无视这一日期,马丁福勒所说的今天和八年前一样重要。 Fowler没有声明你应该将持久性混合到域对象中,恰恰相反:

“还值得强调的是,将行为放入域对象不应该与使用分层将域逻辑与持久性和表示责任等事物分离的可靠方法相矛盾。”

你应该再次阅读这篇文章,因为这篇文章很好地描述了这种反模式,但我会在你所要求的背景下为你总结一下:

如果要创建域模型,是的,您的域对象应该包含业务逻辑和状态,并且应该通过传达业务含义的方法来更改域实体的状态。贫血领域模型是一种反模式,因为你会产生额外一层课程的成本,但你并没有从中获益。为什么要在使用活动记录样式方法(数据集等)时传达完全相同的意图时,必须使用域图层对数据库进行映射?所以这篇文章没有说你应该有一个“学生对象”,但它说如果你这样做,你应该明确地将状态添加到该类。

如果您还没有为您的域建模,那么文章中关于没有一组对象来表示您的模型的观点可能会因为当前可用的技术而有点混乱。有很棒的工具可以毫不费力地在一组POCO和数据库(Nhibernate,EF,Simple Data,Massive,Dapper等)之间移动数据,所以在回顾中我会说你最终会得到一组在今天的大多数解决方案中,“实体”的真正区别在于它是仅仅是数据库模型还是真实的域模型。

我将通过向您展示域入口点(命令处理程序)和域模型之间的交互示例来结束。下面显示的方法位于命令处理程序中,该命令处理程序使用更改域中某些内容的请求。请注意,您的域代码层只是获取域实体并在域上调用一个方法?这一点非常重要,因为我们正在建模的工作流程完全封装在域中,而不是在您的域代码中或其他任何地方:

    public void Handle(AddEmailAddressForAlerts command)
    {
        var agent = _repository.GetAgent(command.AgentKey.AgentId);
        agent.AddEmailAddressForAlerts(new EmailAddress(command.EmailAddress));
    }

答案 1 :(得分:1)

注意日期 - 引用超过八年。

Martin Fowler显然是一个非常聪明的家伙,我喜欢这篇文章的观点,但是要把它当作一粒盐。将状态和行为封装在一起通常是一件好事,但应该根据分层考虑进行平衡。持久性与业务逻辑不同。我还有一个单独的持久层;我不会将持久性放在模型对象中。

教条应该受到各种形式的挑战。要注意别人的想法,但要自己思考。