[英]Configuring implicits in Scala
I have typeclass: 我有类型类:
trait ProcessorTo[T]{
def process(s: String): T
}
and its implementation 及其实现
class DefaultProcessor extends ProcessorTo[String]{
def process(s: String): String = s
}
trait DefaultProcessorSupport{
implicit val p: Processor[String] = new DefaultProcessor
}
To make it available for using I created 为了使其可用于我创建的
object ApplicationContext
extends DefaultProcessorSupport
with //Some other typeclasses
But now I have to add a processor which performs some DataBase - read. 但是现在我必须添加一个执行某些数据库的处理器-读取。 The DB URL etc are placed in condifguration file that is available only a runtime . DB URL等放置在配置文件中,该文件仅在运行时可用 。 For now I did the following. 现在,我做了以下工作。
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)
}
It works for me, but I'm not sure about this technique. 它对我有用,但是我不确定这种技术。 Looks strange for me a little bit. 对我来说有点奇怪。 Is it a bad practice? 这是不好的做法吗? If so, what would be a good solution? 如果是这样,什么是好的解决方案?
I am a bit confused by the requirements as DbProcessor
is missing the process implementation(???) and trait ProcessorTo[T]
is missing start method which is defined in DbProcessor
. 我对要求有些困惑,因为DbProcessor
缺少流程实现(???),而特征ProcessorTo[T]
缺少DbProcessor
定义的启动方法。 So, I will assume the following while answering: the type class has both process
and start
methods 因此,在回答时,我将假设以下内容:类型类同时具有process
和start
方法
Define a type class: 定义一个类型类:
trait ProcessorTo[T]{
def start(config: Config): Unit
def process(s: String): T
}
Provide implementations for the type class in the companion objects: 在伴随对象中提供类型类的实现:
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
}
}
and use it in your ApplicationContext
as follows: 并按如下所示在您的ApplicationContext
使用它:
object ApplicationContext {
def configure[T](config: Config)(implicit ev: ProcessorTo[T]) = ev.start(config)
}
This is a nice blog post about Type Classes: http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html 这是一篇有关类型类的不错的博客文章: http : //danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html
I don't really see why you need start
. 我真的不明白为什么你需要start
。 If your implicit DbProcessor
has a dependency, why not make it an explicit dependency via constructor? 如果您的隐式DbProcessor
具有依赖关系,为什么不通过构造函数使其成为显式依赖关系呢? I mean something like this: 我的意思是这样的:
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)
}
Or if you like Cake pattern, you can do something like this: 或者,如果您喜欢蛋糕模式,则可以执行以下操作:
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)
}
So the only thing you do in your ApplicationContext
is providing actual implementation of the DbConfig
trait. 因此,您在ApplicationContext
所做的唯一一件事就是提供DbConfig
特性的实际实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.