Преимущества шаблона тортов:
- В отличие от DI-решений на основе файлов конфигурации, сопоставление контрактов с реализациями выполняется во время компиляции, что уменьшает проблемы с нахождением классов и совместимостью.Тем не менее, многие механизмы DI имеют альтернативную функцию конфигурации в коде
- Сторонние библиотеки не используются.Самостоятельные аннотации, позволяющие использовать шаблон, являются функцией родного языка.Специальный синтаксис не используется для извлечения реализации контракта
- Забвение указания реализации для компонента, необходимого для другого компонента, приводит к ошибке времени выполнения - просто проверьте эту статью http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html и попробуйте не указыватьодин из компонентов или указание черты вместо конкретного класса в любом из примеров шаблонов тортов или даже забывание инициализировать значение, соответствующее необходимому компоненту
Однако, чтобы воспользоваться этими преимуществами, вам нужночтобы более строго придерживаться архитектуры шаблона - проверьте ту же статью и обратите внимание на черты обертывания, которые содержат фактические контракты и реализации.
Ваши примеры не являются строго шаблоном торта.В вашем случае вы могли бы просто использовать наследование для создания реализаций для ваших признаков и использовать отдельные классы для каждого компонента DAO.В шаблоне «торт» потребительский код будет таким же компонентом, как и код DAO, а код, собирающий зависимости, будет отдельно от него.
Чтобы проиллюстрировать шаблон «торт», вам необходимо добавить классы потребления (слой домена или пользовательский интерфейс) к вашему примеру.Или в случае, если ваши компоненты DAO получили доступ к функциям друг друга, вы могли бы проиллюстрировать шаблон торта на одном только DAO.
, если коротко,
trait OrderDAOComponent {
val dao: OrderDAO
trait OrderDAO {
def create: Order
def delete(id: Int): Unit
//etc
}
}
trait OrderDAOComponentImpl extends OrderDAOComponent {
class OrderDAOJDBCImpl extends OrderDAO {
def create: Order = {/*JDBC-related code here*/}
def delete(id: Int) {/*JDBC-related code here*/}
//etc
}
}
//This one has a dependency
trait OrderWebUIComponentImpl {
this: OrderDAOComponent =>
class OrderWebUI {
def ajaxDelete(request:HttpRequest) = {
val id = request.params("id").toInt
try {
dao.delete(id)
200
}
catch {
case _ => 500
}
}
}
}
//This matches contracts to implementations
object ComponentRegistry extends
OrderDAOComponentImpl with
OrderWebUIComponentImpl
{
val dao = new OrderDAOJDBCImpl
val ui = new OrderWebUI
}
//from some front-end code
val status = ComponentRegistry.ui.ajaxDelete(request)
Подробнее на вашем примере.Я думаю, что это может быть больше похоже на торт, если:
trait DatabaseContext { val dataSource:Datasource }
trait OrderDAOComponent {this:DatabaseContext =>
trait OrderDAOImpl {
... // use dataSource of DatabaseContext
}
}
trait ProductDAOComponent {this:DatabaseContext =>
trait ProductDAOImpl {
... // use dataSource of DatabaseContext
}
}
object Registry extends OrderDAOComponent with ProductDAOComponent with DatabaseContextImpl {
val dataSource = new DatasourceImpl //if Datasource is a custom trait, otherwise wrapping needed
val orderDAO = new OrderDAOImpl
val productDAO = new ProductDAOImpl
}
//now you may use them separately
Registry.orderDAO.//