繁体   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