Лучший способ обработать валидацию полей объекта = ›Either / Try (scala 2.10) / ValidationNEL (scalaz)

Предположим, что объект построен с использованием шаблона построителя.

Этот шаблон построителя будет содержать build метод, ориентированный на проверку полей, а затем на преобразование в целевой тип.

Эта проверка может быть реализована с использованием:

  • Either[FailureObject, TargetObject] тип
  • Try[TargetObject] (новая функция из Scala 2.10)
  • Validation[FailureObject, TargetObject] или ValidationNEL[FailureObject, TargetObject] из библиотеки scalaz

Я читал, что одним из основных преимуществ типа Validation перед Either является то, что Validation может накапливать сбои "из коробки".

А как же «новый» Try способ? Я заметил, что Try также имеет "монадические" методы "из коробки", такие как map, flatMap и т.д. ... чего действительно не хватало с типом Either без помощи Projection.

Таким образом, я могу представить, что каждый метод проверки поля возвращает Try[FieldType], а точнее, в случае любого сбоя, Try[SpecificFieldExceptionType]; этот вложенный, содержащий поле сообщения String и поле rootCause, которое может накапливаться в build методе.

Используя Scala 2.10, можно или нужно Try на практике заменить библиотеку проверки scalaz простой проверкой, такой как шаблон построителя?

** ИЗМЕНИТЬ * ***

Читая Try исходный код, кажется, что Try не может накапливать несколько исключений и, следовательно, ориентирован на безотказную работу. Даже Try.flatMap возвращает потенциальную предыдущую неудачу и поэтому не имеет понятия накопления:

def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]]

В отличие от ValidationNEL, который обрабатывает функцию накопления.

Есть подтверждения?


person Mik378    schedule 27.02.2013    source источник


Ответы (1)


Есть компромиссы:

  • scalaz.Validation может накапливать ошибки типа E для Semigroup[E] экземпляра. Он предназначен для использования как Applicative, например:

    (fragileFoo |@| fragileBar) { case (foo, bar) => doSomething(foo, bar) }
    

    У него есть методы map и flatMap, смещенные в сторону Success, поэтому вы можете удобно использовать его в for-понимании. Однако для него не определен экземпляр Monad, поэтому его нельзя использовать в каких-либо материалах более высокого порядка (например, вы не можете использовать его с преобразователями монад). Однако этот недостаток не кажется проблемой для вас.

  • scalaz.\/, о котором вы не упомянули, действительно образует Monad (опять же, со смещением в сторону Right). Но когда он используется как Applicative, он не накапливает отказы, как Validation.

  • util.Try похож на scalaz.\/, специализируется на Throwable. Хотя в нем снова отсутствует накопление ошибок, в нем есть понятие восстановления после ошибок. Однако для вашего варианта использования "шаблон строителя" кажется, что это может быть не очень полезно.

  • Наконец, util.Either не стоит рассматривать по сравнению с тремя другими вариантами: поскольку он не смещен в одну или другую сторону, вы должны явно и последовательно просить left или right проекцию каждый раз, когда вы хотите сделать что-то монадическое.

Я предполагаю, что для вашей ситуации scalaz.Validation является наиболее подходящим выбором.

person mergeconflict    schedule 30.04.2013
comment
Не могу представить лучшего ответа = ›очень хорошо объяснено! Большое спасибо :) Действительно, я выбрал Validation для работы с моим Builder. - person Mik378; 30.04.2013