Моя цель — проверить поля User
в apply
методе object
перед созданием одного эффективного экземпляра 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
из 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 и сохранить этот механизм проверки?
-----ОБНОВЛЕНИЕ----
Как упомянул @Travis Brown, намерение использовать внешний class
для моего UserValidator
может показаться странным. На самом деле, я ожидаю, что валидатор будет макетным, и поэтому я вынужден использовать композицию поверх trait
/abstract class
.