我有类型类:
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
但现在我必须添加一个执行某些DataBase的处理器 - 读取。数据库URL等位于condifguration文件中, 仅可用于运行时 。现在我做了以下事情。
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)
}
它对我有用,但我对这种技术不太确定。对我来说有点奇怪。这是一种不好的做法吗?如果是这样,那将是一个很好的解决方案?
答案 0 :(得分:1)
由于DbProcessor
缺少流程实现(???)而特质ProcessorTo[T]
缺少DbProcessor
中定义的start方法,因此我对这些要求感到有些困惑。因此,我会在回答时假设以下内容:类型类同时具有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
答案 1 :(得分:1)
我真的不明白为什么你需要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)
}
或者如果你喜欢Cake pattern,你可以这样做:
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
特质的实际实施。