我正在编写一段代码,我觉得这些代码变得非常复杂。
我有一个接受参数的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()
}
这很有效。但我觉得它太冗长和笨拙。我想以更清洁的方式写这篇文章。
答案 0 :(得分:1)
TLDR:从代码中删除继承。
我不明白为什么你需要baseImpl: ContextWriter[Context]
,只是删除这个隐含的,并且总是要求更精确的上下文。 call
成为:
def call[T: ContextWriter](message: String)(implicit context: T) = {
ContextWriterUtil.log(message, context)
}
要使其正常工作,您需要更新web
和mobile
以明确指定类型参数。即使这个类型参数的单个实例化使代码编译,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")
}
通过将Context
和ContextWriter
合并为一个隐式输入,您可以获得明确的输入。例如,为什么不在实例化ContextWriter
时使用“Context
参数,并完成它?