【发布时间】:2021-10-14 08:34:52
【问题描述】:
我了解什么是 VO(不可变、无身份……)。但我有几个问题来自与同事的讨论。
A) 验证 - 它应该有多精确?
我应该在 VO 中添加哪些类型的验证?只有basic 还是all? VO 的一个很好的例子是 Email 带有一些 regexp 验证。我已经看过很多次了。我曾开发过几个大/中型应用程序,而 regexp 还不够好,因为:
- system-A:电子邮件的域名已验证,例如
test@gmali.com在无效电子邮件中,因为域gmali.com不存在 - system-B:我们有“临时电子邮件服务”的禁止域列表(服务),因为我们想避免“虚假帐户”
我无法想象将这种验证放入 VO,因为它需要网络通信,而且 VO 会很复杂(而且速度很慢)。
B) 验证:名称、标题、字符串...是 VO 的长度部分吗?
程序员可以使用旧的string 数据类型。我可以将 VO 成像为NotEmptyString,但是将值对象创建为:
-
FirstName(有长度限制的非空字符串) -
Surname(有长度限制的非空字符串) -
StreetName(有长度限制的非空字符串)
FirstName 和Surname 之间没有区别,因为在应用程序中我们无法确定是否有人在表格中交换了名字和姓氏。 Robert 可以是名字也可以是姓氏...
class Person
{
private string $firstName; // no VO for firstName
// or
private FirstName $firstName; // VO just for firstName & length validation
// or
private NotEmptyString $firstName; // VO - no max length validation
// or
private StringLength50 $firstName; // same as FirstName, different name for sharing
}
哪种方法最好,为什么?
C) VO 副本:为实体参数提供“类型安全”?
这点和上一点类似。
这样创建类是否是一种好习惯:
class Surname extends Name
{
}
class FirstName extends Name
{
}
只是“化名”VO?
D) 持久性:读取存储的 VO
这一点与第一点密切相关:A) 验证 - 它应该有多精确?。我坚信存储在我的“存储引擎”(DB)中的内容是有效的——毫无疑问。当在“持久性步骤”期间验证所有内容时,我看不出有任何理由再次验证 VO。即使是复杂/写得不好的正则表达式也可能成为性能杀手——在用户电子邮件中列出 N 百个。 我迷路了……我应该只验证基本的东西并在持久化和读取期间使用相同的 VO,还是应该为这些情况使用 2 个单独的 VO?
E) 持久性/管理:系统中类似于“上帝”的东西。
根据我的经验:在实际系统中,具有更高权限的用户有时可以绕过验证规则,这又与 A) 点有关:
- 您(作为系统的普通用户)可以在今天起 30 天内进行在线预订
- 管理员用户可以在线预订任何日期
我应该只使用Date / FutureDate VO 还是什么?
F) 持久性:映射到数据库数据类型
将 VO 和 DB(存储引擎)数据类型紧密绑定是一种好习惯吗?
如果 FirstName 只能有 50 个字符,是否应该将其定义/映射到 VAR_CHAR(50)?
谢谢。
【问题讨论】:
-
这真的应该分成几个不同的问题,而不是一个问题有六个部分。
标签: validation domain-driven-design value-objects