我的目标是在创建一个有效实例之前验证'方法User中的字段:objectapplyUser
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.
}
}
我选择使用Validationfrom Scalaz7来积累潜在的非法参数/错误。
以下代码中的一个缺点是 Scalaz7 API 强制我让验证器自己创建实例。但是,通过遵循单一责任原则,这显然不是它的作用。它的作用只是验证字段并返回一些错误列表。
让我们首先展示我的实际代码(作为参考,Empty****对象只是一些case object扩展UserCreationFailure):
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 并保留此验证机制?
-----更新----
class正如@Travis Brown 所提到的,为我使用外部设备的意图UserValidator可能看起来很奇怪。实际上,我希望验证器是可模拟的,因此,我不得不在trait/上使用组合abstract class。