我的目标是在创建有效的User
实例之前,在object
的apply
方法中验证User
的字段:
case class User(String userName, String password)
object User {
def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = {
//call UserValidator's validate() method here and initialize effective User instance.
}
}
我选择使用Scalaz7中的Validation
来累积潜在的非法参数/错误。
以下代码的一个缺点是,Scalaz7 API强制我使验证器创建实例。然而,按照单一职责原则,显然这不是它的角色。它的角色应该只是验证字段并返回一些错误列表。
让我们先介绍我的实际代码(Empty****
对象只是一些扩展UserCreationFailure
的case object
):
class UserValidator(val userName: String, val password: String)
extends CommonValidator[UserCreationFailure] {
def validate(): ValidationNel[UserCreationFailure, User] = {
(checkForUserName ⊛
checkForPassword)((userName, password) => new User(userName, password)
}
private def checkForUserName: ValidationNel[UserCreationFailure, String] = {
checkForNonEmptyString(userName) {
EmptyUserName
}
}
def checkForPassword: ValidationNel[UserCreationFailure, String] = {
checkForNonEmptyString(password) {
EmptyPassword
}
}
}
我会尽力为您提供帮助,以下是您需要翻译的内容:
我所期望的仅仅是返回这段代码片段:
(checkForUserName ⊛ checkForPassword)
并将相应的结果带入我的
User
类中,以便通过以下方式创建有效实例:def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = {
userValidator(username, password).validate()((userName, password)(new User(userName, password))
}
实际上,使用SRP可能更加友好。
但是(checkForUserName ⊛ checkForPassword)
返回完全的private
类型:
private[scalaz] trait ApplicativeBuilder[M[_], A, B]
,
因此我无法控制class
的类型。
因此,我被迫直接将用户的创建过程与其关联。
我应该如何保持SRP并保持这种验证机制呢?
-----更新-----
正如@Travis Brown所提到的,使用外部class
来进行UserValidator
可能看起来很奇怪。 实际上,我希望验证器可以被mockable,因此我被迫使用组合而不是trait
/abstract class
。
UserValidator
可以进行模拟。整个目标是提供一个可模拟的UserValidator
,以适应关于User
类的单元测试。 - Mik378UserValidator
类,但让User
类进行适当的不同验证方法调用,就像你所展示的那样。非常感谢 :) - Mik378