使用特征在Scala中混合核心库

时间:2017-07-11 08:10:11

标签: scala oop traits

我正在Scala开展多个SBT项目。我将核心内容提取到单独的SBT项目中。这包括处理配置,第三方库(init RMQ客户端,init Redis客户端等)和一些模型。

所以我组织了一些事情,例如在trait中加载配置然后我在需要它的地方混合这个特性,然后使用config trait中定义的Configuration方法,它为特定环境加载配置(基于环境变量)。我为数据库做了同样的事情,所以我加载PostgreSQL,打开连接,然后在我需要的地方混合使用该特性,并使用database方法,我可以用它来执行查询等。

你认为这是好方法吗?优点是我不必在每个项目中处理数据库连接和初始化,而且代码也要短得多。但是,关闭连接存在一个问题。在哪里关闭数据库混合的特征中的连接?

对此主题的任何帮助表示赞赏。感谢

阿梅尔

1 个答案:

答案 0 :(得分:1)

关于连接,你应该在完成连接后关闭它们(返回池),这与混合实现是正交的。

至于配置等,我喜欢这种方法,但问题在于,大多数时候你想要加载config之类的东西是单身,但如果你只是做像

这样的事情
  trait Configuration { 
     val config = loadConfig
  }

  class Foo with Configuration
  class Bar with Configuration
  val f1 = new Foo
  val f2 = new Foo
  val b1 = new Bar
  val b2 = new Bar

然后,您最终会加载配置的四个不同副本。 解决此问题的一种方法是将loadConfig委托给单个对象:

 object Configuration {
    val config = loadConfig
 }
 trait Configuration { 
    def config = Configration.config
 }

这样可行,但是使单元测试和覆盖功能变得更加困难(如果我希望有时从数据库加载配置怎么办?)

另一种可能性是代理类:

trait Configuration {
  def loadConfig: Config
  lazy val config: Config = loadConfig
}

class ConfigurationProxy(cfg: Configuration) extends Configuration {
   def loadConfig = cfg.config
}

object Main extends App with Configuration {
   def loadConfig = ??? // executed only one per application 
   ...
}

class Foo extends ConfigurationProxy(Main)
class Bar extends ConfigurationProxy(Main)

val f1 = new Foo
val f2 = new Foo
val b1 = new Bar
val b2 = new Bar

现在,所有四个变量都在查看相同的Config实例。 但是如果你在某个地方有一个需要Configuration的函数,你仍然可以通过以下任何一个:

def connectToDB(cfg: Configuration) = ???

connectToDB(Main)
connectToDB(f1)
connectToDB(b2)