我正在使用允许管理员定义包含字段的表单的系统。然后,使用定义的表格将数据输入系统。有时,表单是由用户通过GUI填写的,有时,表单是根据另一个系统报告的值来填写的。
对于每个字段,管理员可以定义一个验证规则,以限制该字段的允许值。验证规则可以是“在字段中输入的值必须为True或False”到“在字段中输入的值必须存在于数据库表B的A列中”的任何内容。管理员可以随时更改字段的验证规则。
在这种情况下,您认为最适合验证每个字段正确填写的位置是什么?我目前有两种主要方法:
选项1:在域模型中验证
每个字段对象将包含管理员指定的验证规则。Field对象还将引用IValidator。尝试设置字段的值时,字段会将给定的值和验证规则传递给IValidator。如果给定的值无效,则将在另一个系统的GUI /接口中引发ValidationException并进行适当处理。
优点:
- 强大的保护功能,防止字段被意外分配违反验证规则的值
缺点:
数据访问层需要能够绕过验证并构造违反当前验证规则的字段。尽管管理员更改了字段的验证规则,但我们仍然需要能够基于旧数据构造Field对象,例如,当渲染多年前填充的表单时。每当我们存储字段时,都可以通过存储当前的验证规则来解决此问题。
在这种设计中,Field模型通过IValidator间接链接到数据访问层/存储库。服务/存储库的领域模型的注入似乎被普遍令人难以接受的。
选项2:在服务中验证
尝试确保所有尝试设置字段值的尝试都通过可确保验证规则成立的服务。如果违反了验证规则,则抛出ValidationException。
当然,当创建以前一直保存在数据库中的字段对象时,数据访问层将不会使用服务。
优点:
不违反“不要将服务/存储库注入您的域模型”的思想。
保留字段时,无需保留当前的验证规则。该服务可以简单地查询该字段的当前验证规则;查看历史记录数据时,字段的值不会更改。
缺点:
- 不能保证应该使用服务设置字段值的所有逻辑实际上都这样做。我认为这是一个主要缺点。似乎要做的就是有人写“ thisField.setValue(thatField.getValue())”,并且可能会违反thisField的验证规则,而没有人明智。当数据访问层将要保留字段时,可以通过确保字段的值与验证规则匹配来缓解这种情况。
我目前更喜欢选项#1,而不是选项#2,主要是因为我将其视为业务逻辑,并认为选项2带来了将不良数据引入系统的更大风险。您更喜欢哪个选项,或者是否有比上述两个选项更适合这种情况的设计?
编辑(验证的复杂性)
目前出现的验证案例相对简单。字段值必须是例如数字,日期,带时间的日期,或者是数据库列中的现有值。但是,我怀疑复杂性会随着时间逐渐增加。例如,验证解决方案的构建必须考虑国际化-诸如Date之类的内容可能会以特定于语言环境的语法输入。
我现在决定继续使用选项#1,尝试注意不要为域模型分配太多职责。那些面临类似情况的人可能还想查看相关问题分层体系结构中的验证和授权以及数据输入验证-在哪里?多少?。