Validation 使用Scalaz 7在Scala中验证类的内聚方法
我的目标是在创建一个有效的Validation 使用Scalaz 7在Scala中验证类的内聚方法,validation,scala,single-responsibility-principle,scalaz7,Validation,Scala,Single Responsibility Principle,Scalaz7,我的目标是在创建一个有效的用户实例之前,验证对象的应用方法中的用户字段: case class User(String userName, String password) object User { def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = { //call UserValidator's validate() method here and initi
用户
实例之前,验证对象
的应用
方法中的用户
字段:
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.
}
}
我选择使用Validation
fromScalaz7来积累潜在的非法参数/错误
下面代码中的一个缺点是ScalaZ7API强迫我让验证器自己创建实例。然而,通过遵循单一责任原则,它显然不是它的角色。它的作用是验证字段并返回一些错误列表
让我们首先介绍一下我的实际代码(作为参考,空****
对象只是一些案例对象
扩展用户创建失败
):
我希望只返回以下代码片段:
(checkForUserName ⊛ checkForPassword)
并将适当的结果带到myUser
类中,允许通过执行以下操作创建有效实例:
def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = {
userValidator(username, password).validate()((userName, password)(new User(userName, password))
}
事实上,它将与SRP更加友好
但是(checkForUserName⊛ checkForPassword)
返回一个完全私有的
类型:
private[scalaz]trait ApplicativeBuilder[M[\uz],A,B]
因此,我无法掌握返回的类的类型
因此,我不得不直接将用户的创建与之关联
我如何保持SRP和这种验证机制
----更新----
正如@Travis Brown提到的,为我的UserValidator
使用外部类的意图可能看起来很奇怪。实际上,我希望验证器是可模拟的,因此,我不得不使用组合而不是trait
/抽象类
我不确定我是否理解为什么首先需要一个专用的UserValidator
类。在这种情况下,我更可能将所有通用验证代码捆绑到一个单独的特性中,并让我的User
同伴对象(或我想负责创建User
实例的任何其他部分)扩展该特性。下面是一个速写:
import scalaz._, Scalaz._
trait Validator[E] {
def checkNonEmpty(error: E)(s: String): ValidationNel[E, String] =
if (s.isEmpty) error.failNel else s.successNel
}
sealed trait UserCreationFailure
case object EmptyPassword extends UserCreationFailure
case object EmptyUsername extends UserCreationFailure
case class User(name: String, pass: String)
object User extends Validator[UserCreationFailure] {
def validated(
name: String,
pass: String
): ValidationNel[UserCreationFailure, User] = (
checkNonEmpty(EmptyUsername)(name) |@| checkNonEmpty(EmptyPassword)(pass)
)(apply)
}
然后:
scala> println(User.validated("", ""))
Failure(NonEmptyList(EmptyUsername, EmptyPassword))
scala> println(User.validated("a", ""))
Failure(NonEmptyList(EmptyPassword))
scala> println(User.validated("", "b"))
Failure(NonEmptyList(EmptyUsername))
scala> println(User.validated("a", "b"))
Success(User(a,b))
如果您有大量的用户
特定验证逻辑,您不想污染用户
对象,我想你可以把它分解成一个UserValidator
trait,它可以扩展你的泛型Validator
,并被User
扩展。为什么我要处理组合而不是trait(继承),是因为我希望我的UserValidator
是可模仿的。整个目标是提供一个mockable
UserValidator
,以适合我关于User
类的单元测试。当然,我们不能模拟一个精确类的任何特征/超类。我喜欢你的解决方案,尽管我认为保持组合,因此使用外部UserValidator
类,但是让User
类进行适当的不同验证方法调用,正如您所介绍的。非常感谢:)
scala> println(User.validated("", ""))
Failure(NonEmptyList(EmptyUsername, EmptyPassword))
scala> println(User.validated("a", ""))
Failure(NonEmptyList(EmptyPassword))
scala> println(User.validated("", "b"))
Failure(NonEmptyList(EmptyUsername))
scala> println(User.validated("a", "b"))
Success(User(a,b))