DDD: где разместить логику персистентности и когда использовать отображение ORM - PullRequest
13 голосов
/ 17 января 2011

Мы долго и пристально изучаем наши (Java) шаблоны веб-приложений.В прошлом мы страдали от чрезмерно анемичной объектной модели и чрезмерно процедурного разделения между контроллерами, службами и DAO, когда между ними перемещались простые объекты значений (в основном, просто пакеты данных).Мы использовали декларативный (XML) управляемый ORM (Hibernate) для сохранения.Все управление объектами осуществлялось в DAO.

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

Во-первых, вещи, в которых я увереннее:

  • У нас будут "тонкие" контроллеры спереди, которыеработать только с HTTP и HTML - формами обработки, проверкой, логикой пользовательского интерфейса.

  • У нас будет слой сервисов бизнес-логики без сохранения состояния, который реализует общие алгоритмы или логику, не зная UI,но очень хорошо осведомлен (и делегировал) модель предметной области.

  • У нас будет более богатая модель предметной области, которая содержит состояние, отношения и логику, присущие объектам в этой предметной модели..

Вопрос заключается в настойчивости.Ранее наши сервисы вводились (через Spring) в DAO и использовали методы DAO, такие как find () и save (), для выполнения постоянства.Однако более богатая модель домена, по-видимому, подразумевает, что объекты должны знать, как сохранять и удалять себя, и, возможно, что службы более высокого уровня должны знать, как находить (запрашивать) объекты домена.

Здесь несколько вопросови возникают неопределенности:

  • Мы хотим внедрить DAO в доменные объекты, чтобы они могли делать this.omeDao.save (this) в методе save ()?Это немного неловко, поскольку доменные объекты не являются одиночными, поэтому нам понадобятся фабрики или настройки DAO после создания.При загрузке сущностей из базы данных это становится грязным.Я знаю, что Spring AOP может быть использован для этого, но я не смог заставить его работать (используя Play! Framework, другую линию экспериментов), и это кажется довольно грязным и волшебным.

  • Должны ли мы вместо этого хранить DAO (репозитории?) Полностью раздельно, наравне с сервисами бизнес-логики без сохранения состояния?Это может иметь некоторый смысл, но это означает, что если «сохранить» или «удалить» являются неотъемлемыми операциями объекта домена, объект домена не может выразить их.

  • Мы простополностью отказаться от DAO и использовать JPA, чтобы позволить сущностям управлять собой.

В этом заключается следующая тонкость: довольно удобно отображать сущности с использованием JPA.Игра!Framework также дает нам хороший базовый класс сущности с такими операциями, как save () и delete ().Однако это означает, что наши сущности модели предметной области довольно тесно связаны со структурой базы данных, и мы передаем объекты с большим количеством логики постоянства, возможно, вплоть до уровня представления.Если ничего другого, это сделает модель предметной области менее пригодной для повторного использования в других контекстах.

Если мы хотим избежать этого, нам понадобится какое-то отображение DAO - либо с использованием простого JDBC (или по крайней мереSpring JdbcTemplate), или использующий параллельную иерархию объектов базы данных и «бизнес» сущностей, с DAO, которые всегда копируют информацию из одной иерархии в другую.

Какой здесь уместный выбор дизайна?

Martin

Ответы [ 2 ]

3 голосов
/ 17 января 2011

Ваши вопросы и сомнения вызывают здесь интересную тревогу, я думаю, вы зашли слишком далеко в своей интерпретации «модели богатого домена».Богатство не заходит так далеко, как подразумевает, что логика персистентности должна обрабатываться объектами домена, другими словами, нет, они не должны знать, как сохранять и удалять себя (по крайней мере, явно, хотя Hibernate фактически добавляет некоторую логику персистентности).прозрачно).Это часто называют постоянным невежеством.

Я предлагаю сохранить существующую систему инъекций DAO (это полезно для модульного тестирования) и оставить постоянный уровень как есть, пытаясь переместить некоторую бизнес-логику вваши сущности , где это подходит .Хорошей отправной точкой для этого является выявление агрегатов и установление ваших агрегатных корней.Они часто содержат больше бизнес-логики, чем другие объекты.

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

1 голос
/ 17 января 2011

Я не эксперт по Java, но я использую NHibernate в своем коде .NET, поэтому мой опыт должен быть напрямую переведен в мир Java.

При использовании ORM (как вы упомянули в Hibernate) для создания приложения Design-Driven Design одна из хороших (я не скажу лучших) практик заключается в создании так называемых служб приложений между UI и Доменом. Они похожи на бизнес-объекты без сохранения состояния, о которых вы упоминали, но не должны содержать почти никакой логики. Они должны выглядеть так:

public void SayHello(int id, String helloString)
{
    SomeDomainObject target = domainObjectRepository.findById(id); //This uses Hibernate to load the object.

    target.sayHello(helloString); //There is a single domain object method invocation per application service method.

    domainObjectRepository.Save(target); //This one is optional. Hibernate should already know that this object needs saving because it tracks changes.
}

Любые изменения в объектах, содержащихся в DomainObject (также добавляющих объекты в коллекции), будут обрабатываться Hibernate.

Вам также понадобится какая-то AOP для перехвата вызовов методов службы приложений и создания сеанса Hibernate до выполнения метода и сохранения изменений после его завершения без исключений.

Вот действительно хороший пример, как сделать DDD в Java здесь . Он основан на примере задачи из «Синей книги» Эрика Эванса . Пример кода класса логики приложения здесь .

...