【发布时间】:2011-12-06 09:58:47
【问题描述】:
我的编程语言是 C#。我有一个关于我的域模型中的持久性无知的问题。
假设我有一个这样的人员类:
public class Person
{
private string email;
public string Email
{
get { return email; }
set { email = value; }
}
public Person(string email)
{
this.email = email;
}
}
现在,在我的域模型中,有一条规则是不能有两个人拥有相同的电子邮件地址。因此,当实例化一个新人时,这需要在更改电子邮件属性时进行验证。所以我想知道你将如何在你对持久性无知的域层中解决这样的验证。我目前所做的是使用工厂模式进行人员实例化,我在其中注入人员存储库。在那里我可以搜索具有相同电子邮件地址的其他人。像这样:
public class PersonFactory
{
private static readonly IPersonRepository personRepository;
public Person CreateNewPerson(string email)
{
Person personWithSameMail = personRepository.GetPersonByEmail(email);
if (personWithSameMail != null)
throw new ApplicationException("Email already exists.");
return new Person(email);
}
public PersonFactory(IPersonRepository personRepository)
{
this.personRepository = personRepository;
}
}
但使用此解决方案,更改人员电子邮件地址(可以是有效的商业案例)时的检查仍然不包括在内。此外,Person 类仍然公开了一个公共构造函数,并且通过绕过工厂,仍然可以使用重复的电子邮件地址。
任何优雅的解决方案?
附:致所有以数据为中心的人:不,我不想在数据访问层验证欺骗电子邮件;)
更新:
无论如何,这整个问题可能已经过时了。根据域模型上下文检查重复的电子邮件总是需要知道所有人的“东西”——一个根。 “某物”可以是地址簿,也可以是包含所有拥有电子邮件地址的人的整个世界。因此,也许我混淆了程序员对问题的技术优雅解决方案的需求,这只是因为缺乏完整且经过深思熟虑的域模型而存在。这里可以是这种情况吗?不只是一个人的电子邮件地址在太空中漂浮(嘿,太空将是我在这里的总根;))只是为了生存的乐趣?但是,如果这将是一个真实的商业案例,例如地址簿应用程序,那么地址簿将是人员的聚合根,因此可以检查其内部集合中的所有人员,以确保没有重复的电子邮件地址。
【问题讨论】:
-
为什么不将构造函数设为内部并在更新时检查电子邮件地址?而且我认为将存储库提供给工厂并不是一个好的解决方案。致电工厂的服务功能应检查电子邮件地址是否已存在。
-
@WouterdeKort:我不同意您的评论:(1) 将 ctor 设为内部无济于事。它仍然允许创建具有重复邮件地址的用户。 (2) 使调用工厂的方法有效地删除该业务规则。现在由调用者执行此规则。这只是非常糟糕的 API 设计
-
@DanielHilgarth 他明确提到公共构造函数是一个问题。工厂应该构造一个具有所有依赖项和所需值的对象。将业务逻辑与工厂混合在一起我称之为糟糕的设计。
-
@WouterdeKort:我不同意。工厂是封装某种类型的所有对象需要满足的业务规则的理想场所