Я все еще пытаюсь изучить Scala Cake Pattern. Мне кажется, что это дает вам преимущество централизации вашей конфигурации "Компонентов", а также возможность предоставления стандартных реализаций для этих компонентов (которые, конечно, переопределяемы).
Тем не менее, использование признаков самонастройки для описания зависимостей, кажется, смешивает область проблем. Цель компонента (я думаю) состоит в том, чтобы абстрагировать различные реализации этого компонента. Но листинг зависимостей, описанный в Компоненте, сам по себе является проблемой реализации.
Например, скажем, у меня есть база данных, полная виджетов, реестра, которая позволяет мне искать определенные виды виджетов и какой-то алгоритм, который использует реестр для обработки виджетов:
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 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, потому что это то, что требует алгоритм верхнего уровня.
Я что-то упустил? В тот момент, когда я использую self-type в любом из моих Компонентов, я объявляю, что все возможные реализации должны использовать те же зависимости.
Кто-нибудь еще сталкивается с этой проблемой? Что такое торт-подобный способ его решения?
Спасибо!