Jeśli nie musiałeś zwracać innej wiadomości dla przypadku Brak, byłby to idealny przypadek użycia dla dla zrozumienia. W twoim przypadku prawdopodobnie będziesz używał monady walidacyjnej, takiej jaką można znaleźć w Scalaz. Przykład (http://scalaz.github.com/scalaz/scalaz-2.9.0-1-6.0/doc.sxr/scalaz/Validation.scala.html).
W programowaniu funkcjonalnym nie powinieneś wyrzucać wyjątków, ale pozwolić funkcjom, które mogą zawieść, zwrócić A [A, B], gdzie zgodnie z konwencją A jest typem wyniku w przypadku niepowodzenia, a B jest typem wyniku w przypadek sukcesu. Następnie można dopasować lewy (a) lub prawy (b), aby odpowiednio obsłużyć dwie sprawy.
Monadę walidacyjną można postrzegać jako rozszerzoną [A, B], w której zastosowanie kolejnych funkcji walidacji da wynik, lub pierwsze niepowodzenie w łańcuchu wykonania.
sealed trait Validation[+E, +A] {
import Scalaz._
def map[B](f: A => B): Validation[E, B] = this match {
case Success(a) => Success(f(a))
case Failure(e) => Failure(e)
}
def foreach[U](f: A => U): Unit = this match {
case Success(a) => f(a)
case Failure(e) =>
}
def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] = this match {
case Success(a) => f(a)
case Failure(e) => Failure(e)
}
def either : Either[E, A] = this match {
case Success(a) => Right(a)
case Failure(e) => Left(e)
}
def isSuccess : Boolean = this match {
case Success(_) => true
case Failure(_) => false
}
def isFailure : Boolean = !isSuccess
def toOption : Option[A] = this match {
case Success(a) => Some(a)
case Failure(_) => None
}
}
final case class Success[E, A](a: A) extends Validation[E, A]
final case class Failure[E, A](e: E) extends Validation[E, A]
Twój kod teraz można refaktoryzować za pomocą monady Walidacja na trzy warstwy sprawdzania poprawności. należy w zasadzie wymienić mapę z walidacji tak:
def jsonValidation(request:Request):Validation[BadRequest,String] = request.asJson match {
case None => Failure(BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Expecting JSON data")
)
case Some(data) => Success(data)
}
def featureValidation(validatedJson:Validation[BadRequest,String]): Validation[BadRequest,Feature] = {
validatedJson.flatMap {
json=> json.asOpt[Feature] match {
case Some(feature)=> Success(feature)
case None => Failure(BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Invalid feature entity")
)))
}
}
}
a następnie łańcucha je jak na poniższym featureValidation(jsonValidation(request))
dziękuję za odpowiedź, kod, który napisałem, kompiluje, ale wydaje mi się, że jest trochę zbyt skomplikowany w tym przykładzie ... – opensas
A jak zachować różne odpowiedzi "BadRequest" na różnych poziomach? Wydaje się, że to kluczowa kwestia, która uniemożliwia bezpośrednie podejście. Zastanawiam się, czy dopasowanie wzorców jest do tego? –
Zgadza się. W imperatywnym języku po prostu nie udałoby mi się opuścić metody, gdy tylko znajdę błąd. Ale gdy próbowałem to zrobić, stanąłem przed kilkoma problemami z oświadczeniem zwrotnym http://stackoverflow.com/questions/11929485/scala-problems-with-return-statement/11929616#11929616 – opensas