Домен управляемый дизайн и роль фабричного класса - PullRequest
43 голосов
/ 17 февраля 2009

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

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

Где фабрика вписывается в следующие рамки:
Пользовательский интерфейс> Приложение> Домен> Сервис> Данные

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

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

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

Ответы [ 6 ]

55 голосов
/ 21 февраля 2009

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

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

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

Вот пример. Я использую паттерн Holub's 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.

Теперь вот как фабрика может использоваться в каждом случае.

В 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
}

В вашем доменном слое возможно модульное тестирование:

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());

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

Домен.

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

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

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

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

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

Кстати, иерархия, которую вы описали, вероятно, должна быть UI> Приложение> Доменные службы> Домен> Инфраструктура (Данные)

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

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

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

12 голосов
/ 25 сентября 2012

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

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

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

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

userRepository.Insert(user);

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

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

6 голосов
/ 22 февраля 2009

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

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

  • Некоторому слою необходимо создать объект с некоторой регулярностью. и
  • Только тот слой знает, когда его создавать или с какими настройками и
  • Только какой-то другой слой точно знает, что создать.
3 голосов
/ 17 февраля 2009

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

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

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

Обновление

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

2 голосов
/ 22 февраля 2009

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

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

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

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

Интерфейс пользователя> Приложение> Домен

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

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

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

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

1 голос
/ 23 декабря 2016

Я вижу, что уровень Application Services отвечает за создание новых объектов, вызывая фабрику для этого. Следовательно, интерфейс фабрики сущностей определен в модуле службы приложений, а фактическая реализация - это служба инфраструктуры, так же, как и постоянство. Чтобы получить четкое представление об общих службах приложений и службах доменов и инфраструктурных службах, я получил много ясности, наблюдая за этим: Боб Мартин Руби Средний Запад 2011

...