[英]Configuring implicits in Scala
我有類型類:
trait ProcessorTo[T]{
def process(s: String): T
}
及其實現
class DefaultProcessor extends ProcessorTo[String]{
def process(s: String): String = s
}
trait DefaultProcessorSupport{
implicit val p: Processor[String] = new DefaultProcessor
}
為了使其可用於我創建的
object ApplicationContext
extends DefaultProcessorSupport
with //Some other typeclasses
但是現在我必須添加一個執行某些數據庫的處理器-讀取。 DB URL等放置在配置文件中,該文件僅在運行時可用 。 現在,我做了以下工作。
class DbProcessor extends ProcessorTo[Int]{
private var config: Config = _
def start(config: Config) = //set the configuration, open connections etc
//Other implementation
}
object ApplicationContext{
implicit val p: ProcessorTo[Int] = new DbProcessor
def configure(config: Config) = p.asInstanceOf[DbProcessor].start(config)
}
它對我有用,但是我不確定這種技術。 對我來說有點奇怪。 這是不好的做法嗎? 如果是這樣,什么是好的解決方案?
我對要求有些困惑,因為DbProcessor
缺少流程實現(???),而特征ProcessorTo[T]
缺少DbProcessor
定義的啟動方法。 因此,在回答時,我將假設以下內容:類型類同時具有process
和start
方法
定義一個類型類:
trait ProcessorTo[T]{
def start(config: Config): Unit
def process(s: String): T
}
在伴隨對象中提供類型類的實現:
object ProcessorTo {
implicit object DbProcessor extends ProcessorTo[Int] {
override def start(config: Config): Unit = ???
override def process(s: String): Int = ???
}
implicit object DefaultProcessor extends ProcessorTo[String] {
override def start(config: Config): Unit = ???
override def process(s: String): String = s
}
}
並按如下所示在您的ApplicationContext
使用它:
object ApplicationContext {
def configure[T](config: Config)(implicit ev: ProcessorTo[T]) = ev.start(config)
}
這是一篇有關類型類的不錯的博客文章: http : //danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html
我真的不明白為什么你需要start
。 如果您的隱式DbProcessor
具有依賴關系,為什么不通過構造函數使其成為顯式依賴關系呢? 我的意思是這樣的:
class DbConfig(val settings: Map[String, Object]) {}
class DbProcessor(config: DbConfig) extends ProcessorTo[Int] {
// here goes actual configuration of the processor using config
private val mappings: Map[String, Int] = config.settings("DbProcessor").asInstanceOf[Map[String, Int]]
override def process(s: String): Int = mappings.getOrElse(s, -1)
}
object ApplicationContext {
// first create config then pass it explicitly
val config = new DbConfig(Map[String, Object]("DbProcessor" -> Map("1" -> 123)))
implicit val p: ProcessorTo[Int] = new DbProcessor(config)
}
或者,如果您喜歡蛋糕模式,則可以執行以下操作:
trait DbConfig {
def getMappings(): Map[String, Int]
}
class DbProcessor(config: DbConfig) extends ProcessorTo[Int] {
// here goes actual configuration of the processor using config
private val mappings: Map[String, Int] = config.getMappings()
override def process(s: String): Int = mappings.getOrElse(s, -1)
}
trait DbProcessorSupport {
self: DbConfig =>
implicit val dbProcessor: ProcessorTo[Int] = new DbProcessor(self)
}
object ApplicationContext extends DbConfig with DbProcessorSupport {
override def getMappings(): Map[String, Int] = Map("1" -> 123)
}
因此,您在ApplicationContext
所做的唯一一件事就是提供DbConfig
特性的實際實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.