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

Разработка домена и роль класса factory

Я не понимаю, каковы роли и ответственность класса factory. Я достаточно знаю, что класс factory должен быть resposible для создания объектов домена (совокупный корень) вместе с связанными с ним объектами и объектами значения.

Но что мне не понятно, где слой factory лежит с DDD-архитектурой? Должно ли factory звонить непосредственно в репозиторий, чтобы получить его данные или библиотеку сервисов?

Где factory вписывается в следующую структуру:
UI > Приложение > Домен > Сервиs > Данные

Кроме того, поскольку factory является единственным местом, разрешенным для создания объекта, вы не получите круговые ссылки, если хотите создать свои объекты в своих слоях данных и услуг?

Если роль класса factory заключается в создании объекта, то какие преимущества имеет уровень сервиса?

Я задал много вопросов и оценил любой ответ. Что мне не хватает, это пример приложения, демонстрирующий, как все слои в проекте, управляемом доменом, собрались вместе... Есть ли что-нибудь там?

4b9b3361

Ответ 1

Но мне непонятно, где слой factory "лежит с DDD архитектура? Если factoryвызов непосредственно в репозиторий получить свои данные или услугу библиотека?

factory должен быть универсальным магазином для создания объектов домена. Любая другая часть кода, которая должна это сделать, должна использовать factory.

Как правило, существует как минимум три источника данных, которые используются как входные данные в конструкцию объекта factory для объекта: ввод из пользовательского интерфейса, результаты запросов от настойчивости и запросы, имеющие значение для домена. Поэтому, чтобы ответить на ваш конкретный вопрос, в репозитории будет использоваться factory.

Вот пример. Здесь я использую шаблон Holub Builder. Изменить: игнорировать использование этого шаблона. Я начал понимать, что не слишком хорошо смешивается с фабриками DDD.

// domain layer
class Order
{
    private Integer ID;
    private Customer owner;
    private List<Product> ordered;

    // can't be null, needs complicated rules to initialize
    private Product featured; 

    // can't be null, needs complicated rules to initialize, not part of Order aggregate
    private Itinerary schedule; 

    void importFrom(Importer importer) { ... }

    void exportTo(Exporter exporter) { ... }

    ... insert business logic methods here ...

    interface Importer
    {
        Integer importID();
        Customer importOwner();
        Product importOrdered();
    }

    interface Exporter
    {
        void exportID(Integer id);
        void exportOwner(Customer owner);
        void exportOrdered(Product ordered);
    }
}

// domain layer
interface OrderEntryScreenExport { ... }

// UI
class UIScreen
{
    public UIScreen(OrderEntryDTO dto) { ... }
}

// App Layer
class OrderEntryDTO implements OrderEntryScreenExport { ... }

Вот как выглядит OrderFactory:

interface OrderFactory
{
    Order createWith(Customer owner, Product ordered);
    Order createFrom(OrderEntryScreenExport to);
    Order createFrom(List<String> resultSets);
}

Логика для выбранного продукта и генерация маршрута идут в OrderFactory.

Теперь вот как factory может использоваться в каждом экземпляре.

В OrderRepository:

public List<Order> findAllMatching(Criteria someCriteria)
{
    ResultSet rcds = this.db.execFindOrdersQueryWith(someCriteria.toString());
    List<List<String>> results = convertToStringList(rcds);

    List<Order> returnList = new ArrayList<Order>();

    for(List<String> row : results)
        returnList.add(this.orderFactory.createFrom(row));

    return returnList;
}

В вашем прикладном уровне:

public void submitOrder(OrderEntryDTO dto)
{
    Order toBeSubmitted = this.orderFactory.createFrom(dto);

    this.orderRepo.add(toBeSubmitted);

    // do other stuff, raise events, etc
}

В вашем доменном слое unit test возможно:

Customer carl = customerRepo.findByName("Carl");
List<Product> weapons = productRepo.findAllByName("Ruger P-95 9mm");
Order weaponsForCarl = orderFactory.createWith(carl, weapons);

weaponsForCarl.place();

assertTrue(weaponsForCarl.isPlaced());
assertTrue(weaponsForCarl.hasSpecialShippingNeeds());

Где factory вписывается в следующая структура: UI > Приложение > Домен > Сервиs > Данные

Домен.

Кроме того, поскольку factory является единственным место, разрешенное для создания объекта вы не получите круговые ссылки если вы хотите создать свои объекты в ваших слоях данных и услуг?

В моем примере все зависимости распространяются сверху вниз. Я использовал Принцип инверсии зависимостей (ссылка PDF), чтобы избежать проблемы, о которой вы говорите.

Если роль класса factoryдля создания объекта, то какие выгоды имеет ли сервисный уровень?

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

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

Кстати, описанная вами иерархия должна, вероятно, быть UI > App > Domain Services > Domain > Infrastructure (Data)

Я задал много вопросов и оценивать любой ответ. То, что я отсутствует примерное приложение, которое демонстрирует, как все слои в проект приводов с поддержкой домена вместе... Есть что-нибудь есть?

Применение дизайна и шаблонов Driven Driven от Jimmy Nilsson - отличный комплимент Эрику Эвансу Разработка доменов. В нем много примеров кода, хотя я не знаю, есть ли акцент на расслоении. Сложность может быть сложной и почти тема отдельно от DDD.

В книге Эванса есть очень маленький пример расслоения, который вы, возможно, захотите проверить. Layering - это шаблон предприятия, и Мартин Фаулер писал Шаблоны архитектуры корпоративных приложений, которые также могут оказаться полезными.

Ответ 2

Разница между репозиторием и factory заключается в том, что репозиторий представляет собой абстрактное постоянное хранилище, а factory отвечает за создание объекта.

Итак, скажем, я зарегистрирую пользователя. Я получу свой пользовательский объект из factory

IUser user = userFactory.Create(name, email);

Затем передайте его в репозиторий, который будет отвечать за его работу.

userRepository.Insert(user);

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

Кроме того, это позволяет репозиториям сфокусироваться на их типе сущности, и, следовательно, использование дженериков становится очень мощным.

Ответ 3

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

Я использую factory, когда:

  • Некоторый слой должен создать объект с некоторой регулярностью. и
  • Только тот слой знает, когда его создавать, или с какими настройками и
  • Только некоторые другие слои точно знают, что создавать.

Ответ 4

Ребята из DDD и я могу поспорить об этом, но в основном идея этого класса "factory" заключается в выпуске объектов домена. объекты домена затем получают доступ к данным и становятся частью "модели" домена, с которым вы работаете.

Приложение содержит пользовательский интерфейс и т.д., это не иерархия наследования.

Будьте осторожны с этим "видом" оператора; многие люди думают, что, поскольку они МОГУТ использовать наследование, они ДОЛЖНЫ использовать наследование. Агрегация ( "содержит" или "имеет", а не "есть" ) часто лучше.

Update

Не обязательно. Подумайте о том, что говорит вам домен: это что-то вроде "Мне нужен продукт, и я знаю номер продукта продукта. Когда продукт factory завершен, я хочу получить полностью заполненный объект, представляющий мой продукт". Когда вы создаете свой объект Product, что ему нужно сделать, чтобы быть допустимым объектом продукта, представляющим определенный продукт?

Ответ 5

Должен ли factory напрямую обращаться в репозиторий, чтобы получить его данные или библиотеку сервисов?

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

Где factory вписывается в следующая структура: UI > Приложение > Домен > Сервиs > Данные

Не уверен, где происходит это расслоение, слои не фиксированы в DDD, но я бы сказал, что вам лучше всего сфокусироваться на этом стиле

UI > Приложение > Домен

Внутри домена у вас есть несколько типов объектов, и я бы установил правила относительно отношений между ними:

  • Фабрики должны пройти все, что им нужно, чтобы выполнить свою работу, поэтому я бы не пригласил их в другие службы или репозитории в большинстве случаев.
  • В большинстве случаев сущности не должны связываться с репозиториями, вместо этого службы (или другие верхние уровни) должны нести ответственность за эту работу.
  • Сущности не должны вызывать сервисы, службы сидят поверх объектов/значений объектов/спецификаций и координируют их по мере необходимости.
  • Службы внутри домена находятся в координации, они не содержат существенного поведения в домене/бизнесе.

Если роль класса factory заключается в создании объекта, то какие преимущества имеет уровень сервиса?

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

Ответ 6

Я вижу, что уровень приложений-служб несет ответственность за создание новых объектов, вызвав factory для этого. Следовательно, интерфейс factory определяется в модуле Application Service, а фактическая реализация - это инфраструктурный сервис, аналогично тому, как это происходит. Для получения четкой идеи об обслуживании общих приложений и об обслуживании доменных служб и инфраструктурных сервисах я получил большую ясность, наблюдая за этим: Bob Martin Ruby Midwest 2011