Scala Cake Pattern:将大型组件拆分为单独的文件

时间:2012-04-20 18:51:36

标签: scala cake-pattern

我想使用Cake Pattern将某些软件系统的各个部分拆分成组件,使其完全模块化,如this article中所提出的那样。在最简单的情况下,我想要一些可模拟的组件,比如说Logging,Config,Database,Scripts等可能会互相使用。代码可能看起来像

trait AbstractConfig {
  def config: AbstractConfigInterface
  trait AbstractConfigInterface {
    def test: Unit
  }
}

trait SomeConfig extends AbstractConfig {
  this: Core =>  
  def config = SomeConfigImplementation
  object SomeConfigImplementation extends AbstractConfigInterface {
    def test = println("conf.test method called")
  }
}

trait AbstractDatabase {
  def database: AbstractDatabaseInterface
  trait AbstractDatabaseInterface {
    def connect: Unit
  }
}

trait SomeDatabase extends AbstractDatabase {
  this: Core =>
  def database = SomeDatabaseImplementation
  object SomeDatabaseImplementation extends AbstractDatabaseInterface {
    def connect = {
      println("connect method called")
      core.conf.test
    }
  }
}

trait Core {
  this: AbstractDatabase with AbstractConfig =>
  def core = CoreInterface
  object CoreInterface {
    def db = database
    def conf = config
  }
}

object app extends Core with SomeDatabase with SomeConfig

object Run {
  def main(args: Array[String]) = {
    app.core.db.connect
  }
}

此处数据库和配置组件(SomeConfigSomeDatabase特征)是可插入的,如果需要,可以更改为其他一些实现。他们的实现可以访问保存数据库和配置的core对象,因此数据库可以在需要时访问配置,反之亦然。

所以问题是:如果像SomeDatabase这样的特性变得很大并且不适合单个文件,那么如何将其拆分为保留对core对象的访问的单独类?更具体地说,假设我需要将SomeDatabase中的连接方法中的一些代码移到另一个文件中:

// SomeDatabase.scala
trait SomeDatabase extends AbstractDatabase {
  this: Core =>
  def database = SomeDatabaseImplementation
  object SomeDatabaseImplementation extends AbstractDatabaseInterface {
    def connect = {
      val obj = new SomeClass()
    }
  }
}

// SomeClass.scala in the same package
class SomeClass {
    core.conf.test // Does not compile - how to make it work??
}

SomeClass是SomeDatabase如何工作的实现细节,所以我显然不想把它作为特性并将其混合到应用程序中。有没有办法为core提供SomeClass对象的访问权限?


一些相关链接:

  1. Dependency Injection vs Cake Pattern by Jan Machacek
  2. Real World Scala: Dependency Injection by Jonas Boner
  3. Dependency Injection in Scala: Extending the Cake Pattern by Adam Warsky
  4. Scalable Component Abstractions by Martin Odersky & Matthias Zenger

1 个答案:

答案 0 :(得分:2)

最简单的方法是将Core作为构造函数参数传递给SomeClass

// SomeDatabase.scala
trait SomeDatabase extends AbstractDatabase {
  this: Core =>
  def database = SomeDatabaseImplementation
  object SomeDatabaseImplementation extends AbstractDatabaseInterface {
    def connect = {
      val obj = new SomeClass(SomeDatabase.this) // pass it here
    }
  }
}

// SomeClass.scala in the same package
class SomeClass(coreComp: Core) { // use it here
    coreComp.core.conf.test
}

有趣的是,我真的只想传递CoreInterfaceAbstractConfigInterface,但事实上它们是内部类型确实很难。