一个有趣的讨论在我刚刚输入这个问题时出现了。但我不认为它回答了我的问题。
我一直在使用 .NET MVC3,其中最好拥有贫血模型。视图模型和编辑模型最好是愚蠢的数据容器,你只需将其从控制器传递到视图即可。任何类型的应用程序流程都应该来自控制器,而视图则处理 UI 相关问题。在 MVC 中,我们不希望模型中出现任何行为。
然而,我们也不希望控制器中出现任何业务逻辑。对于大型应用程序,最好将域代码与模型、视图和控制器(以及 HTTP)分离并独立。因此,有一个单独的项目,在任何其他东西之前提供一个域模型(包含根据 DDD 组合的实体和值对象)。
我尝试过几次离开贫血模型,转向领域代码更丰富的模型,但我考虑放弃了。对我来说,似乎同时包含数据和行为的实体类违反了 SRP 原则。
例如,假设有一个非常常见的场景,即组成电子邮件。给定某个事件,根据 EmailTemplate、EmailAddress 和自定义值,域的责任是组成 EmailMessage 对象。模板作为一个具有属性的实体存在,并且用户提供自定义值作为输入。出于论证的目的,假设 EmailMessage 的 FROM 地址可以由外部服务提供(IConfigurationManager.DefaultFromMailAddress)。在这种要求下,似乎富领域模型可以将组成 EmailMessage 的责任交给 EmailTemplate:
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的本意--在我看来,EmailTemplate只是用于存储数据(主题格式、正文格式、附件以及可选的发件人/回复地址)。最终,我将这个方法重构为专门的类,该类的唯一职责是在给定先前参数的情况下组合EmailMessage,并且我对此非常满意。实际上,我开始更喜欢贫血领域,因为它可以帮助我保持责任的分离,从而使类和单元测试更短、更简洁、更集中。似乎让实体和其他数据对象“不具备行为”对于分离责任是有好处的。或者我偏离了正确的方向?