微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Scala蛋糕图案鼓励硬编码依赖?

我还在尝试学习Scala的蛋糕图案。在我看来,它可以让您集中配置“组件”以及为这些组件提供认实现(这当然可以覆盖)的优势。

然而,使用自我类型的特征来描述依赖关系似乎混合了关注点。组件(我认为)的目的是抽象出该组件的不同实现。但是组件中描述的依赖关系本身就是一个实现问题。

例如,假设我有一个数据库包含小部件,一个注册表,允许我查找特定类型的小部件,以及一些使用注册表处理小部件的算法:

case class Widget(id: Int,name:String)

trait DatabaseComponent {
  def database: (Int => Widget) = new DefaultDatabase()

  class DefaultDatabase extends (Int => Widget) {
    // silly impl
    def apply(x: Int) = new Person(x,"Bob")
  }
}

trait RegistryComponent {
  this: DatabaseComponent =>  // registry depends on the database

  def registry: (List[Int] => List[Widget]) = new DefaultRegistry()

  class DefaultRegistry extends (List[Int] => List[Widget]) {
    def apply(xs: List[Int]) = xs.map(database(_))
  }
}

trait AlgorithmComponent {
  this: RegistryComponent =>  // algorithm depends on the registry

  def algorithm: (() => List[Widget]) = new DefaultAlgorithm()

  class DefaultAlgorithm extends (() => List[Widget]) {
    // look up employee id's somehow,then Feed them
    // to the registry for lookup
    def apply: List[Widget] = registry(List(1,2,3))
  }
}

现在你可以把它放在一些中央配置中:

object Main {
  def main(args: Array[String]) {
    val algorithm = new AlgorithmComponent() with RegistryComponent with DatabaseComponent

    val widgets = println("results: " + algorithm.processor().mkString(","))
  }
}

如果我想要更改为不同的数据库,我可以通过更改我的mixin来轻松地注入它:

val algorithm = new AlgorithmComponent() with RegistryComponent with SomeOtherDatabaseComponent

但是,如果我想在不使用数据库的不同的注册表组件中混合怎么办?

如果我尝试使用不同的(非认)实现子类化RegistryComponent,则RegistryComponent将坚持要包含一个DatabaseComponent依赖项。而且我必须使用RegistryComponent,因为这是顶级的AlgorithmComponent需要的。

我错过了什么吗?在我的任何组件中使用自我类型的时刻,我声明所有可能的实现都必须使用相同的依赖关系。

有没有人遇到这个问题?蛋糕般的解决方法是什么?

谢谢!

解决方法

使用蛋糕模式,至少在 example I always go to,您应该将组件的界面定义与其认实现分开。这干净地将接口的依赖与实现的依赖关系分开。

trait RegistryComponent {
  // no dependencies
  def registry: (List[Int] => List[Widget])
}

trait DefaultRegistryComponent extends RegistryComponent {
  this: DatabaseComponent =>  // default registry depends on the database

  def registry: (List[Int] => List[Widget]) = new DefaultRegistry()

  class DefaultRegistry extends (List[Int] => List[Widget]) {
    def apply(xs: List[Int]) = xs.map(database(_))
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐