我有一名员工在一个集合中拥有多个地址。
public class Employee
{
public string Name { get; set; }
public AddressCollection Addresses { get; }
}
public class AddressCollection : IEnumerable<Address>
{
private readonly Employee employee;
private IList<Address> items = new List<Address>();
public void AddAddress(Address address)
{
if (items.Contains(address)) return;
address.Employee = employee;
items.Add(address);
}
public void RemoveAddress(Address address)
{
items.Removce(address);
}
/// further IEnumerable implementations
}
public class Address
{
public AddressType Type { get; set; }
public City City { get; set; }
public string Street { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime ValidTo { get; set; }
}
public enum AddressType
{
Default,
ShippingAddress
}
一次只能有一种类型的某个地址有效。因此,当在1-1-2009到15-1-2009之间添加类型默认有效地址,然后在10-1-2009到15-1-2009之间另一个类型默认有效的地址时,需要抛出异常。
从DDD的角度来看,最好的方法是什么?当然,在 AddAddress方法中,我可以遍历现有地址并抛出异常。
但是,由于需要在表示层上检查此业务规则以向用户显示消息,因此我不应该使用内部以及表示层中可以使用的规范吗?
你会如何解决这个问题?
答案 0 :(得分:5)
首先,我将摆脱您的AddressCollection类并在Employee上实现其成员。
为了验证这样的规则,我推荐specification pattern。它不需要像维基百科文章那么复杂,它可以简单地是:
public class CanAddAddressToEmployeeSpec
{
public bool IsSatisfiedBy(Address candidate)
{ // logic to check address }
}
然后,您可以使用该类检查在添加地址之前是否可以将地址添加到Employee中,以便您的Employee对象不会进入无效状态。我还经常将一个Messages属性添加到规范中,如果IsSatisifiedBy为false,则返回解释。
如果您需要更多信心,可以为EmployeeAddressesAreValidSpec
创建一个类似的规范,将Employee作为IsSatisfiedBy的候选参数,并在持久化数据之前检查它。
答案 1 :(得分:0)
我建议使用Microsoft模式和实践团队发布的企业库中的Validation Application Block。
这允许您将验证逻辑放在域对象上(维护DDD),还可以填充对象,然后然后询问它是否有效,而不是抛出异常。
我不确定您的UI是什么,但验证应用程序块可以与ASP.NET,Windows窗体和WCF集成。
答案 2 :(得分:0)
我同意里奇的观点。开始查看验证应用程序块。 This article可能对您有所帮助,因为它描述了如何将VAB与O / RM框架集成。虽然本文侧重于LINQ to SQL和Entity Framework,但我希望NHibernate没有任何意外。