我的目标是在创建一个有效的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.
}
}我选择使用Validation from 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和保持这种验证机制?
-----UPDATE
正如@Travis所提到的,为我的UserValidator使用外部class的意图可能看起来很奇怪。实际上,我希望验证器是可模拟的,因此,我不得不在trait/abstract class上使用组合。
发布于 2013-05-05 20:34:31
我不知道为什么首先需要一个专用的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))如果您有大量的User-specific验证逻辑,并且不希望污染您的User对象,那么我想您可以将其分解为一个UserValidator特性,该特性将扩展您的通用Validator并由User扩展。
https://stackoverflow.com/questions/16386513
复制相似问题