我正在设计库,它应该可以帮助我在未来的项目中设计领域。我制作了一些基本的值对象,例如 EmailAddress 或 PhoneNumber。那些很容易。当这样的值对象可能有不同的规则集来说明它是否有效时,它开始给我带来问题。
让我们在这里使用 Password
作为示例,因为这是我写这个问题的实际原因。在以前的项目中,我在 Password
构造器中验证了密码规则集。但它使这个实现项目变得具体,并且违反了 - 我认为 - 关注分离原则。
我在考虑将 Strategy Patten 作为解决方案。但是以这种方式构建这样的 VO:new Password("123456", new AwfullyLoosePasswordValidationStrategy())
对我来说听起来很糟糕。我也在考虑 VO setValidationStrategy(PasswordValidationStrategy strategy)
中的 static setter,但这仍然反对关注点分离,对我来说听起来很奇怪。
所以响应的第一部分是——我认为——密码应该只做基本的完整性检查,比如 isNullOrEmptyString
,仅此而已。但是我什么时候应该进行适当的验证?在实体创建期间?在服务层的某个地方坚持之前?实体的想法对我来说听起来还不错,但是 setPassword(Password password
) 如何知道我想使用的策略?我尽量避免在我的项目中使用单例,几乎所有的事情都是通过那里的 DI 完成的。
tl;dr:我应该在哪里验证无法在其构造函数中验证的值对象?
最佳答案
Where should I validate Value Object that cannot be validated in its constructor?
我不相信你有这样的东西。您永远不应该创建无效的值对象。构造函数(如果您愿意,可以替代工厂或工厂方法)验证参数,如果它们是可接受的,则创建一个格式正确、不可变的值对象,然后您就完成了。
I was thinking of Strategy Patten as solution here. But construction such VO in this way: new Password("123456", new AwfullyLoosePasswordValidationStrategy()) sounds terrible to me.
我不知道在任何情况下策略模式在值对象中有意义。如果值类型的查询需要策略,您似乎更有可能将策略作为查询的参数传递,而不是将其作为类型固有的。
也就是说,在我看来,您已经非常接近正确的想法了;你只是倒退了
PasswordValidator validator = new AwfullyLoosePasswordValidator();
Password password = validator.createPassword("123456");
也就是说,工厂根据您的策略验证输入,如果可以接受,那么它会将输入传递给密码构造函数(它也执行自己的检查)。
或者,您可以将密码策略作为实体创建的一部分而不是密码创建的一部分来实现
class EntityFactory {
private final PassswordValidator passwordValidator;
Entity create(Password password) {
passwordValidator.check(password);
return new Entity(password);
}
Entity idea sounds not that bad for me, but how setPassword(Password password) would know about strategy I want to use?
现在是一个非常重要的问题,您应该非常仔细地研究这个问题。
因为如果你仔细看需求,你很可能会发现 setPassword() 方法并不在明显的地方。
如果您将密码建模为您实体的属性,那么该实体还需要了解密码策略,它应该如何知道?更改密码策略是否需要更改每个实体?您可以拥有两个具有不同密码策略等的实体吗?
或者,您的系统中可能有一个集合拥有密码策略。在这种情况下,该集合也可能负责所有密码(无论如何都在该策略的范围内)。也就是说,密码不是实体的属性,它实际上可能是字典中的一个值,您可以在字典中使用 entityId 来查找它。
ddd 的重点是使用您的通用语言进行挖掘并与您的领域专家一起审查需求。不要羞于确保您对自己的领域有透彻的了解。
关于java - 具有不同状态的值对象的验证 - 密码大小写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36048922/