刚才我输入这个问题时,出现了一个有趣的线程。我不认为它回答了我的问题。
我一直在使用 .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,我对此更满意。事实上,我开始更喜欢贫血领域,因为它帮助我保持职责分离,使类和单元测试更短、更简洁、更专注。似乎使实体和其他数据对象“没有行为”可以很好地分离责任。还是我在这里偏离轨道?