В моем приложении есть шаблон, который я пытаюсь уменьшить, когда API вызывает соответствующие методы обслуживания.
Вот абстрактный пример:
override def foo(in: FooRequest): Future[FooResponse] =
commandService
.doFoo(in)
.map {
case Success(_) => FooResponse()
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
.recover { case e: Throwable => failureHandler(Status.INTERNAL, e) }
override def bar(in: BarRequest): Future[BarResponse] =
commandService
.doBar(in)
.map {
case Success(_) => BarResponse()
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
.recover { case e: Throwable => failureHandler(Status.INTERNAL, e) }
20times
Итак, как вы можете видеть, здесь есть некоторая возможность применить принципы DRY.
Я мог бы создать функцию, которая принимаетметод обслуживания как функция, а затем выполнить типовые действия, но я не знаю, как работать в заявлении case в будущую карту.
private def executeCommand[A, B, C](
command: A,
f: A => Future[Try[B]],
onSuccess: Try[B] => C): Future[C] =
f(command)
.map(onSuccess)
.recover { case e: Throwable => failureHandler(Status.INTERNAL, e) }
Но это потребовало бы от меня вызова метода следующим образом:
def foo(in: FooRequest) =
executeCommand(
in,
commandService.doFoo, { x: Try[FooSuccess] =>
x match {
case Success(_) => FooResponse(in.requestId)
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
}
Случай сбоя будет повторяться для каждого метода.Я хотел бы добавить это в метод executeCommand, если это возможно.Кроме того, этот подход кажется, что он не удаляет много шаблонного, но я чувствую, что другой подход мог бы.
ОБНОВЛЕНИЕ С ПРИМЕРОМ РЕШЕНИЯ
Спасибо всем за помощь.В итоге мне удалось найти довольно хорошее решение, используя ответ awagen.
def foo(in: FooRequest) =
commandService.doFoo(in).handleResults((pass: FooSuccess) => FooResponse(pass.requestId))
//20 times
implicit private class FooBarServiceHandler[A](future: Future[Try[A]]) {
import scala.language.higherKinds
def handleResults[B](func: A => B): Future[B] =
future.map(onSuccess(func)).recover { case e: Throwable => failureHandler(Status.INTERNAL, e) }
private def onSuccess[B, C](func: B => C): Try[B] => C = {
case Success(resp) => func(resp)
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
}