shj*_*shj 18 dependency-injection scala traits cake-pattern
我还在尝试学习Scala的蛋糕模式.在我看来,它为您提供了集中"组件"配置的优势,以及为这些组件提供默认实现的能力(当然这些组件是可覆盖的).
然而,使用自我类型特征来描述依赖关系似乎混合了关注领域.Component(我认为)的目的是抽象出该组件的不同实现.但是Component中描述的依赖列表本身就是一个实现问题.
例如,假设我有一个装满小部件的数据库,一个允许我查找特定种类小部件的注册表,以及一些使用注册表处理小部件的算法:
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))
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以将它放在一些中央配置中:
object Main {
def main(args: Array[String]) {
val algorithm = new AlgorithmComponent() with RegistryComponent with DatabaseComponent
val widgets = println("results: " + algorithm.processor().mkString(", "))
}
}
Run Code Online (Sandbox Code Playgroud)
如果我想更改为其他数据库,我可以通过更改我的mixin轻松注入:
val algorithm = new AlgorithmComponent() with RegistryComponent with SomeOtherDatabaseComponent
Run Code Online (Sandbox Code Playgroud)
但是......如果我想混合使用不使用数据库的不同注册表组件怎么办?
如果我尝试使用不同的(非默认)实现继承RegistryComponent,则RegistryComponent将坚持我包含DatabaseComponent依赖项.我必须使用RegistryComponent,因为这是顶级AlgorithmComponent所需要的.
我错过了什么吗?我在任何组件中使用自我类型的那一刻,我宣称所有可能的实现都必须使用这些相同的依赖项.
还有其他人遇到过这个问题吗?什么是蛋糕般的解决方法?
谢谢!
lee*_*777 17
使用蛋糕模式,至少通过我总是去的示例,您应该将组件的接口定义与其默认实现分开.这将接口的依赖关系与实现的依赖关系完全分开.
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(_))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2289 次 |
| 最近记录: |