簡體   English   中英

在Scala中配置隱式

[英]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定義的啟動方法。 因此,在回答時,我將假設以下內容:類型類同時具有processstart方法

定義一個類型類:

  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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM