2017-07-26 101 views
0

我有这样的感觉,我可以进一步抽象我的代码,但我有点卡住了。我这样做更像是一个挑战,所以不要担心过早的优化。这是为我的开源库Reactive Kraken斯卡拉,非常相似的类型的抽象逻辑

如果你看看这段代码,我相信你会明白我的意思。

case class Response[T](error: List[String], result: Option[Map[String, T]]) 
case class OrderResponse[T](error: List[String], result: Option[T]) 

def handleRequest[T: JsonFormat](request: HttpRequest): Future[Response[T]] = 
    fireRequest(request) 
    .map(_.parseJson.convertTo[Response[T]]) 
    .recover { case t: Throwable => Response[T](List(t.getMessage), None) } 

def handleOrderRequest[A: JsonFormat](request: HttpRequest): Future[OrderResponse[A]] = 
    fireRequest(request) 
    .map(_.parseJson.convertTo[OrderResponse[A]]) 
    .recover { case t: Throwable => OrderResponse[A](List(t.getMessage), None) } 

这两个函数之间的区别仅仅是它们返回的类型。你会怎么做呢?也许使用更高的 kinded类型?

回答

1

一种方法是统一ResponseOrderResponse

case class Response[T]  (error: List[String], result: Option[Map[String, T]]) 
case class OrderResponse[T](error: List[String], result: Option[T]) 
// === 
type Response[T] = OrderResponse[Map[String, T]] 
case class OrderResponse[T](error: List[String], result: Option[T]) 

,然后OrderResponse功能也一个上Response。但是,我不知道这些类型的语义。

如果这不是理想,一个类型类会做:

trait Recovering[T] { 
    def recover(error: Throwable): T 
} 
object Recovering { 
    def apply[T: Recovering] = implicitly[Recovering[T]] 
} 

implicit def requestsAreRecovering[T]: Recovering[Request[T]] = new Recovering[Request[T]] { 
    override def recover(error: Throwable) = Request[T](List(t.getMessage), None) 
} 
implicit def orderRequestsAreRecovering[T]: Recovering[OrderRequest[T]] = new Recovering[OrderRequest[T]] { 
    override def recover(error: Throwable) = OrderRequest[T](List(t.getMessage), None) 
} 

def handleRequest[T: JsonFormat: Recovering](request: HttpRequest): Future[T] = 
    fireRequest(request) 
    .map(_.parseJson.convertTo[T]) 
    .recover(Recovering[T].recover) 
1

没有抽象,你仍然可以因式分解代码:

case class Response[T](error: List[String], result: Option[Map[String, T]]) 

case class OrderResponse[T](error: List[String], result: Option[T]) 

private def handle[T: JsonFormat, U](request: HttpRequest, recovery: Throwable => U): Future[U] = { 
    fireRequest(request) 
    .map(_.parseJson.convertTo[U]) 
    .recover { case t: Throwable => recovery(t) } 
} 

def handleRequest[T: JsonFormat](request: HttpRequest): Future[Response[T]] = 
    handle(request, {t: Throwable => Response[T](List(t.getMessage), None)}) 

def handleOrderRequest[T: JsonFormat](request: HttpRequest): Future[Response[T]] = 
    handle(request, {t: Throwable => OrderResponse[A](List(t.getMessage), None)})