Подтвердить что ты не робот

Scala Cake Pattern Поощрять жесткозависимые зависимости?

Я все еще пытаюсь изучить 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 в любом из моих Компонентов, я объявляю, что все возможные реализации должны использовать те же зависимости.

Кто-нибудь еще сталкивается с этой проблемой? Что такое торт-подобный способ его решения?

Спасибо!

4b9b3361

Ответ 1

С рисунком торта, по крайней мере, с помощью я всегда перехожу к, вы должны отделить определение интерфейса компонента от его реализации по умолчанию. Это чисто отделяет зависимости интерфейса от зависимостей реализации.

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(_))
  }
}