【问题标题】:Can a "rich domain model" violate the Single Responsibility Principle?“富域模型”会违反单一职责原则吗?
【发布时间】:2012-05-14 08:07:12
【问题描述】:

An interesting thread 是我刚才输入这个问题时出现的。我不认为它回答了我的问题。

我一直在使用 .NET MVC3 进行大量工作,希望有一个贫血模型。视图模型和编辑模型最好作为愚蠢的数据容器,您可以将它们从控制器传递到视图。任何类型的应用程序流都应该来自控制器,视图处理 UI 问题。在 MVC 中,我们不希望模型中有任何行为。

但是,我们也不希望控制器中有任何业务逻辑。对于较大的应用程序,最好将域代码与模型、视图和控制器(以及通常的 HTTP)分开并独立于模型、视图和控制器。因此,有一个单独的项目首先提供域模型(具有实体和值对象,根据 DDD 组合成聚合)。

我已经做了一些尝试,试图从一个贫乏的模型转向更丰富的域代码模型,但我正在考虑放弃。在我看来,拥有既包含数据又包含行为的实体类违反了 SRP。

以网络上一个非常常见的场景为例,撰写电子邮件。给定一些事件,域有责任在给定 EmailTemplate、EmailAddress 和自定义值的情况下编写一个 EmailMessage 对象。模板作为具有属性的实体存在,并且自定义值作为用户输入提供。为了论证,我们还假设 EmailMessage 的 FROM 地址可以由外部服务 (IConfigurationManager.DefaultFromMailAddress) 提供。鉴于这些要求,富域模型似乎可以让 EmailTemplate 负责编写 EmailMessage:

public class EmailTemplate
{
    public EmailMessage ComposeMessageTo(EmailAddress to, 
        IDictionary<string, string> customValues, IConfigurationManager config)
    {
        var emailMessage = new EmailMessage(); // internal constructor
                                            // extension method
        emailMessage.Body = this.BodyFormat.ApplyCustomValues(customValues);
        emailMessage.From = this.From ?? config.DefaultFromMailAddress;
        // bla bla bla
        return emailMessage;
    }
}

这是我对富域模型的尝试之一。但是,在添加此方法后,EmailTemplate 负责包含实体数据属性和撰写消息。它大约有 15 行长,似乎分散了全班学生对成为 EmailTemplate 的真正含义的注意力——IMO 只是存储数据(主题格式、正文格式、附件和可选的发件人/回复地址)。

我最终将此方法重构为一个专门的类,该类的唯一责任是根据前面的参数编写一个 EmailMessage,我对此更满意。事实上,我开始更喜欢贫血域,因为它帮助我保持职责分离,使类和单元测试更短、更简洁、更专注。似乎使实体和其他数据对象“没有行为”可以很好地分离责任。还是我跑偏了?

【问题讨论】:

  • 富域模型只需要足够丰富就可以满足相关上下文。

标签: domain-driven-design single-responsibility-principle anemic-domain-model


【解决方案1】:

支持富域模型而不是贫乏模型的论点取决于 OOP 的价值主张之一,即保持行为和数据彼此相邻。核心好处是封装和凝聚力,有助于推理代码。富域模型也可以被视为information expert 模式的一个实例。然而,所有这些模式的价值在很大程度上是主观的。如果将数据和行为分开对您更有帮助,那么就这样吧,尽管您可能还会考虑其他将查看代码的人。我更喜欢尽可能多地封装。在这种情况下,更丰富的域模型的另一个好处是可以将某些属性设为私有。如果一个属性只被类的一种方法使用,为什么要公开它?

富域模型是否违反 SRP 取决于您对责任的定义。根据 SRP,责任是改变的理由,这本身就需要一个定义。该定义通常取决于手头的用例。您可以声明模板类的职责是成为一个模板,包含所有出现的含义,其中之一是从模板生成消息。模板属性之一的更改可能会影响ComposeMessageTo 方法,这表明这些可能是单一职责。此外,ComposeMessageTo 方法是模板中最有趣的部分。模板的客户不关心方法是如何实现的,也不关心模板类的属性是什么。他们只想根据模板生成消息。这也投票赞成在方法旁边保留数据。

【讨论】:

    【解决方案2】:

    嗯,这取决于你想怎么看。

    另一种方式是:“单一职责原则会违反富领域模型吗?”

    两者都是指南。软件设计中没有任何“原则”。然而,有好的设计和坏的设计。这两个概念可以以不同的方式使用,以实现良好的设计。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2011-11-02
      相关资源
      最近更新 更多