[英]Scala adding dynamic switch to future map
在我的應用程序中,當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)
}
}
你怎么樣這樣做:
def onSuccess[B,C](func: B => C): Try[B] => C = {
{
case Success(resp) => func.apply(resp)
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
}
並傳遞function resp => FooResponse(in.requestId)
或其他用例使用函數中的實際Success結果來生成相應的響應。 這種方式可以避免重復匹配,只是對成功案例和不同類型的結果有不同的解釋(對不起,代碼可以看作有點偽代碼:))
解決這個問題的更好方法是使用部分功能和currying
def executeCommand[A, B, C](f: A => Future[Try[B]])
(handleFailure: PartialFunction[Try[B], C])
(handleSuccess: PartialFunction[Try[B], C])
(command: A)
(implicit executionContext: ExecutionContext): Future[C] = {
val handleResult = handleSuccess.orElse(handleFailure)
f(command).collect(handleResult)
}.recover{
case ex: Throwable => failureHandler(Status.INTERNAL, e)
}
val failureHandlerPf = {
case Failure(e) => failureHandler(Status.INTERNAL, e)
}
val successHandlerFooPf = {
x: FooResponse => x
}
val func1 = executeCommand(failureHandlerPf)
val fooPf = func1(successHandlerFooPf)
override def foo = fooPf(in)
val successHandlerBarPf = {
case x: BarResponse => x
}
val barPf = func1(successHandlerBarPf)
override def bar = barPf(in)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.