Как вы делаете инъекцию зависимостей с шаблоном Cake без hardcoding?

Я только что прочитал и получил удовольствие от статьи с рисунком «Торт» . Однако, на мой взгляд, одной из ключевых причин использования инъекции зависимостей является то, что вы можете изменять компоненты, используемые либо XML-файлом, либо аргументами командной строки.

Как этот аспект DI обрабатывается с помощью шаблона Cake? Примеры, которые я видел, include в себя смешение признаков статически.

Так как перемещение в чертах выполняется статически в Scala, если вы хотите изменить черты, смешанные с объектом, создайте разные объекты на основе некоторого условия.

Возьмем пример канонического шаблона торта. Ваши модули определяются как признаки, а ваше приложение построено как простой объект с кучей функциональности, смешанной в

val application = new Object extends Communications with Parsing with Persistence with Logging with ProductionDataSource application.startup 

Теперь все эти модули имеют приятные декларации самонастройки, которые определяют их межмодульные зависимости, поэтому строка только компилируется, если существуют все межмодульные зависимости, уникальные и хорошо типизированные. В частности, модуль Persistence имеет тип self-type, который говорит, что что-либо, реализующее Persistence, должно также реализовать DataSource, абстрактный признак модуля. Поскольку ProductionDataSource наследуется от DataSource, все отлично, и эта линия построения приложений компилируется.

Но что, если вы хотите использовать другой DataSource, указывая на некоторую локальную базу данных для целей тестирования? Предположим далее, что вы не можете просто повторно использовать ProductionDataSource с разными параметрами конфигурации, загруженными из некоторого файла свойств. Что бы вы сделали в этом случае, это определить новый признак TestDataSource, который расширяет DataSource и вместо этого смешивает его. Вы можете даже сделать это динамически на основе флага командной строки.

 val application = if (test) new Object extends Communications with Parsing with Persistence with Logging with TestDataSource else new Object extends Communications with Parsing with Persistence with Logging with ProductionDataSource application.startup 

Теперь это выглядит немного более подробным, чем хотелось бы, особенно если ваше приложение нуждается в изменении его конструкции на нескольких осях. С положительной стороны вы обычно имеете только один блок условной логики построения, подобный этому в приложении (или в худшем случае один раз за определенный жизненный цикл компонента), поэтому по крайней мере боль минимизируется и отгорожена от остальной части вашей логики.

Scala также является языком скриптов. Таким образом, ваш XML-код конфигурации может быть сценарием Scala. Это безопасный тип и не-разный язык.

Просто посмотрите на запуск:

 scala -cp first.jar:second.jar startupScript.scala 

не так сильно отличается от:

 java -cp first.jar:second.jar com.example.MyMainClass context.xml 

Вы всегда можете использовать DI, но у вас есть еще один инструмент.

Короткий ответ заключается в том, что Scala в настоящее время не имеет встроенной поддержки динамических микшинов.

Я работаю над autoproxy-плагином, чтобы поддержать это, хотя он в настоящее время приостановлен до версии 2.9, когда у компилятора будут новые функции, что делает его намного проще.

Тем временем, лучший способ достичь практически такой же функциональности – это реализовать динамически добавленное поведение в качестве classа-оболочки, а затем добавить неявное преобразование обратно в обернутый элемент.

Пока плагин AutoProxy не станет доступен, одним из способов достижения эффекта является использование делегирования:

 trait Module { def foo: Int } trait DelegatedModule extends Module { var delegate: Module = _ def foo = delegate.foo } class Impl extends Module { def foo = 1 } // later val composed: Module with ... with ... = new DelegatedModule with ... with ... composed.delegate = choose() // choose is linear in the number of `Module` implementations 

Но будьте осторожны, недостатком этого является то, что он более подробный, и вы должны быть осторожны в порядке инициализации, если вы используете var s внутри черты. Другой недостаток заключается в том, что если в Module выше указаны типы, зависящие от пути, вы не сможете легко использовать делегирование.

Но если существует большое количество различных реализаций, которые могут варьироваться, это, вероятно, будет стоить вам меньше кода, чем листинг со всеми возможными комбинациями.

В лифте есть что-то по этим строкам. В основном это код scala, но у вас есть некоторый контроль времени исполнения. http://www.assembla.com/wiki/show/liftweb/Dependency_Injection

  • Когда использовать знак равенства в объявлении метода Scala?
  • Могу ли я получить список времени компиляции всех объектов case, которые происходят из запечатанного родителя в Scala?
  • Каковы отношения между Any, AnyVal, AnyRef, Object и как они отображаются при использовании в Java-коде?
  • Использование def, val и var в scala
  • Отладка Scala-кода с помощью простого-build-инструмента (sbt) и IntelliJ
  • Как применить функцию к кортежу?
  • Функции против методов в Scala
  • Что означает => и () => среднее значение в Scala
  • Скала для странного поведения
  • Шаблон Loaner в Scala
  • Как построить Uber JAR (FAT JAR) с использованием SBT в IntelliJ IDEA?
  • Interesting Posts
    Давайте будем гением компьютера.