我不认为自己是DDD专家,但作为解决方案架构师,请尽可能尝试应用最佳实践。我知道围绕DDD中的(公共)二传手“样式”的赞成和反对有很多讨论,我可以看到论点的两面。我的问题是,我在一个拥有各种技能,知识和经验的团队中工作,这意味着我不能相信每个开发人员都会以“正确”的方式做事。例如,如果我们设计域对象以便通过一种方法来执行对对象内部状态的更改,但提供公共属性设置器,则有人将不可避免地设置该属性而不是调用该方法。使用此示例:
public class MyClass
{
public Boolean IsPublished
{
get { return PublishDate != null; }
}
public DateTime? PublishDate { get; set; }
public void Publish()
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
PublishDate = DateTime.Today;
Raise(new PublishedEvent());
}
}
我的解决方案是将属性设置器设为私有,这是可能的,因为我们用来为对象水合的ORM使用反射,因此它能够访问私有设置器。但是,这在尝试编写单元测试时会出现问题。例如,当我想编写一个单元测试来验证我们不能重新发布的要求时,我需要指出该对象已经发布。我当然可以通过两次调用Publish来做到这一点,但是我的测试假设第一次调用正确实现了Publish。好像有点臭。
让我们使用以下代码使场景更真实一些:
public class Document
{
public Document(String title)
{
if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("title");
Title = title;
}
public String ApprovedBy { get; private set; }
public DateTime? ApprovedOn { get; private set; }
public Boolean IsApproved { get; private set; }
public Boolean IsPublished { get; private set; }
public String PublishedBy { get; private set; }
public DateTime? PublishedOn { get; private set; }
public String Title { get; private set; }
public void Approve(String by)
{
if (IsApproved)
throw new InvalidOperationException("Already approved.");
ApprovedBy = by;
ApprovedOn = DateTime.Today;
IsApproved = true;
Raise(new ApprovedEvent(Title));
}
public void Publish(String by)
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
if (!IsApproved)
throw new InvalidOperationException("Cannot publish until approved.");
PublishedBy = by;
PublishedOn = DateTime.Today;
IsPublished = true;
Raise(new PublishedEvent(Title));
}
}
我想编写验证以下内容的单元测试:
- 除非文件获得批准,否则我无法发布
- 我无法重新发布文档
- 发布时,正确设置了PublishedBy和PublishedOn值
- 发布后,将引发PublishedEvent
如果无法访问设置器,则无法将对象置于执行测试所需的状态。对二传手的开放访问将阻止阻止访问的目的。
您如何解决此问题?