如何在域对象和服务中的验证与UI层中的验证保持干燥
本文关键字:验证 UI 对象 服务 | 更新日期: 2023-09-27 17:57:50
我已经搜索了答案,甚至问了几个关于这个主题的问题,但还没有真正找到正确的答案。如何向UI层公开我的POCO域对象和服务中的验证方法?目前我正在使用网络表单。
例如,我有一个以下域对象:
class Person
{
public string Name { get; set; }
public string Email { get; set; }
public bool IsValidEmail(string email) {}
public bool IsValidName(string name) {}
public bool IsValidPerson()
{
if (IsValidEmail(Email) && IsValidName(Name)) { return true; }
return false;
}
}
和域服务:
class PersonService
{
private Person person;
private PersonRepository pRepo;
public PersonService()
{
person = new Person();
pRepo = new PersonRepository();
}
public AddPerson(Person p)
{
if (p.IsValidEmail(p.Email) && p.IsValidName(p.Name) && !DoesEmailExistInDatabase(p.Email))
{ pRepo.Save(p); }
else
{ throw new ArgumentException(); }
}
public GetPersonByEmail(string email)
{
if (person.IsValidEmail(Email))
{ pRepo.GetByEmail(email)); }
else
{ throw new ArgumentException(); }
}
public bool DoesEmailExistInDatabase(string email) { //code if exists.. }
}
和UI/代码隐藏层:
通过电子邮件联系人员
string emailInput = EmailTextBox.Text;
PersonService pService = new PersonService();
Person p = new Person();
if(p.IsValidEmail(emailInput))
{
Person myPerson = pService.GetPersonByEmail(emailInput);
}
else
{
//give user error here...
}
为域对象中可能需要验证的每个属性创建单独的验证方法是否正确?
域对象和服务中的那些方法应该是静态的吗?这样我就不必创建person的实例来进行验证了?
我是否应该在服务中公开Person域对象的验证,这样用户就不需要知道在哪里查找它们(因为我在服务中放置了一些验证,在POCO中放置了某些验证,这实际上是一个实现问题)?
4.有更好的方法吗?
Re#1-是(这是一种有效的方法),假设域对象最适合"知道"什么是正确的输入。
Re#2-是。
Re#3-这样做没有害处,但是,如果你不相信类外部的东西能够/负责实际的验证,为什么你会相信它会调用验证?
我会在设置值时强制验证,一旦对象中有"好数据",以后就不需要验证了。这导致第4点…
Re#4-以某种方式提供/公开验证的好处是系统的其他部分可以使用它;典型的例子是在UI中,您可以通过在输入或提交时验证输入来提供更好的用户体验。
另一种验证方法是确定好的数据(在总体视图中)是什么样子的,并为其定义一组作为(单独的)公共域级别"服务"存在的规则。验证每个域对象内部的输入是很好的,因为随着时间的推移,随着各个域对象的成熟,您可以更改特定的规则(您可以限制孤立更改的影响)-缺点是您会重复很多规则。
一个常见的服务会解决这个问题,一个服务会说"这就是一个有效的电子邮件地址",任何你的域对象都会听从该服务,告诉他们什么是好的电子邮件地址。
这种方法的"诀窍"是要小心命名验证方法——不要太模糊或模棱两可。例如,您可能会发现大多数具有电子邮件属性的域对象使用一种"主"电子邮件验证方法ValidateGenericEmail()
,但通常情况下,其他对象是具有特殊规则ValidateCorporateEmail()
的特殊对象。没关系,将它们添加到验证服务中,因为这是域层中管理这些规则的中心位置。
然后,你的域对象仍然可以做你以前需要他们做的一切——除了你把规则拉到了一个单独的公共位置。
我只会在表示层上进行验证,并从中清除域模型。因此,域模型假设数据已经过验证(并且已经过验证,不是吗?)。或者您有其他数据来源吗?它会让你的领域模型更加纯粹,你会看到它的核心。但在对象创建时,通过使用保护子句检查构造函数参数来强制执行一些约束是不错的。