2017-05-18 23 views
1

我正在寫一段代碼,我覺得它變得非常複雜。簡化帶有隱含的卷積代碼

我有一個接受參數是一個特質的API。這個特徵可以通過多種類型來實現。此外,這些類中的每一個都需要由專門的處理器來處理。

例如,我創建了一個名爲Context的Trait,它具有兩種實際類型的MobileContext和WebContext。

假設MobileContext和WebContext的記錄方式不同,我們有以ContextWriter [MobileContext]和ContextWriter [WebContext]形式的專門實現。

要求是該方法應該是通用的,但它應該能夠根據特徵的實際類型將調用分派到正確的ContextWriter。

這是我的代碼。

trait Context 
case class WebContext(name: String) extends Context 
case class MobileContext(name: String) extends Context 


trait ContextWriter[T] { 
    def log(message: String, context: T) : Unit 
} 

object ContextWriterUtil { 
    def log[T](message: String, context: T)(implicit writer: ContextWriter[T]) = { 
     writer.log(message, context) 
    } 
} 

object ContextWriterImplicits { 
    implicit val webImpl = new ContextWriter[WebContext] { 
     override def log(message: String, context: WebContext) = println(s"I am in web context ${context} and the message is ${message}") 
    } 
    implicit val mobileImpl = new ContextWriter[MobileContext] { 
     override def log(message: String, context: MobileContext) = println(s"I am in mobile context ${context} and the message is ${message}") 
    } 
    implicit val baseImpl = new ContextWriter[Context] { 
     override def log(message: String, context: Context) = context match { 
     case s: WebContext => { 
      val writer = implicitly[ContextWriter[WebContext]] 
      writer.log(message, s) 
     } 
     case s: MobileContext => { 
      val writer = implicitly[ContextWriter[MobileContext]] 
      writer.log(message, s) 
     } 
     case _ => throw new Exception("don't understand this type") 
     } 
    } 
} 

import ContextWriterImplicits._ 
object MyApplication extends App { 

    // this is the generic method. 
    def call[T <: Context](message: String)(implicit context: T) = { 
     val actualContext = implicitly[Context] 
     ContextWriterUtil.log(message, actualContext) 
    } 
    def web() = { 
     implicit val webContext = WebContext("web") 
     call("I am calling the method") 
    } 
    def mobile() = { 
     implicit val mobileContext = MobileContext("mobile") 
     call("I am calling the method") 
    } 
    web() 
    mobile() 
} 

This Works。但我覺得它太冗長而笨拙。我想用更清晰的方式寫這個。

回答

1

TLDR:從您的代碼中刪除繼承。

我不明白你爲什麼需要baseImpl: ContextWriter[Context],只是刪除這個隱式,總是要求更精確的上下文。 call變爲:

def call[T: ContextWriter](message: String)(implicit context: T) = { 
    ContextWriterUtil.log(message, context) 
} 

對於工作,你需要更新webmobile顯式地指定類型參數。即使有這種類型的參數,使代碼編譯的一個實例,scalac不能夠明白這一點:

def web() = { 
    implicit val webContext = WebContext("web") 
    call[WebContext]("I am calling the method") 
} 

def mobile() = { 
    implicit val mobileContext = MobileContext("mobile") 
    call[MobileContext]("I am calling the method") 
} 

您可能能夠通過組合ContextContextWriter到得到顯式類型的騎一個隱含的。例如,爲什麼不在您的Context實例化時採取「不明確的ContextWriter」的論點,並完成它?