在这里,我们将考虑执行验证的不同方法,什么是上下文验证以及为什么它胜过所有其他方法。
![424ba7fa85bdd54acfc2d4826c368f2d.png](https://img-blog.csdnimg.cn/img_convert/424ba7fa85bdd54acfc2d4826c368f2d.png)
绑定到数据模型的上下文无关的验证
当前大多数框架都迫使我们及其用户将验证放入数据模型中。至少对于我们大多数人来说,默认模式是将验证规则简单地绑定到数据模型中的特定字段。这种方法有什么问题?
考虑一个示例,其中客人注册了新的食物交付订单。该服务背后的公司实际上是在做饭,称为SuperFood。这就是整个用户故事的样子:
SuperFood的后端服务在将内容放入数据库之前必须确保多个约束。其中一项是确保传递电子邮件或电话号码。
现在,假设另一个用户在SuperFood中注册了一个订单,但是这次通过某种聚合服务,将其称为AggreA。尽管要执行的约束条件有所不同,但该命令与在SuperFood网站上注册的命令没有太大不同。例如,传递电话号码对于该聚合器是必不可少的,而电子邮件是可选的。
现在,第三个用户在SuperFood中注册了一个订单,然后她通过其他聚合服务AggreB进行了订购。对于那个,不需要传递电话号码,但是电子邮件是必须的。
因此,我们有以下情况。我有一个订单的单个数据模型,但是至少有三个带有不同约束集的上下文。我可以采用传统方式:引入一个与数据库行相对应的实体,并通过注释或配置文件或我习惯的任何方式施加这些约束。数据模型验证支持以下方法:
Java
1
@ValidContactInfo
2
public class User
3
{
4
private String phoneNumber;
5
6
private String email;
7
8
// ...
9
}
自定义注解ValidContactInfo最终将我们带到自定义验证器,例如ContactInfoValidator。它最清晰的实现反映了产品经理的心智模型,它类似于以下内容(使用伪代码):
Java
1
If order is being registered through site, then either email or phone number must be present.
2
If order is being registered through AggreA, phone is required.
3
If order is being registered through AggreB, email is required.
主要目的是找出在某种程度上它究竟是什么范围内操作的具体方案。
数据模型方式意味着我们应该在验证器中执行此操作,并从实体数据对象中获取字段。这样一来,我相信它是最不受欢迎的一种,因为我们无法使用域模型的强大功能,而必须将验证逻辑驻留在服务类中。简化后,大致如下所示:
Java
1
public class ContactInfoValidator
2
{
3
public boolean isValid(Order order)
4
{
5