2017-07-26 100 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)})