Модели модели домена и уровня обслуживания в P EAA
В шаблонах архитектуры корпоративных приложений Мартин Фаулер рассказывает о двух шаблонах для организации Domain Logic: Модель домена и Уровень обслуживания. Шаблон модели домена - это подход "чистого ООП", где модели (те объекты, которые, вероятно, просматриваются из базы данных с использованием ORM) содержат бизнес-логику (хотя, вероятно, только делегирование логики в другом классе).
![A sample Domain Model]()
Шаблон Service Layer похож на шаблон модели домена, но с тонким слоем перед ним, содержащим бизнес-операции, которые могут быть выполнены. В MVC контроллер будет в основном взаимодействовать с уровнем обслуживания. Я считаю, что большинство хорошо продуманных веб-приложений MVC используют этот шаблон.
![A sample Service Layer]()
Теперь, на мой вопрос. Мартин предполагает, что подход "Модель домена" является более объектно-ориентированным подходом и поэтому лучше. По моему опыту, это очень сложно (см.: Невозможно) реализовать на практике.
Возьмем пример, приведенный на первой диаграмме выше. Существует два "объекта" Contract
и Product
. Они сохраняются в базе данных с помощью mapper. В этом примере есть RecognitionStrategy
. Мартин ставит методы делегирования этой стратегии, которая содержит фактическую бизнес-логику, в самих сущностях; клиент выполняет этот расчет с помощью contract.calculateRecognitions
или contract.recognizedRevenue(someDate)
. При реализации подобных проектов я обычно пишу клиентский интерфейс как strategy.calculateRecognitions(contract)
и strategy.recognizedRevenue(contract, someDate)
. Это делает уровень обслуживания необходимым для координации стратегии и контракта. Используемая конкретная стратегия вводится в службу.
Мартинский подход определенно более привлекателен с точки зрения дизайна, но работа вокруг настройки намного сложнее:
- Передача стратегии при создании экземпляра a
Product
является болью. Вам нужно создать Product
с помощью factory, в котором используется конкретная служба, которая, в свою очередь, передаст ее в объект при его создании.
- Менее мелкомасштабный контроль доступа к базе данных. В зависимости от настроек ORM делегирование
Contract
на Product
может выполнять запрос за Product
. Жесткая загрузка Product
в mapper (или ORM) может быть чрезмерной, когда мы загружаем Contract
, но не намереваемся называть contract.calculateRecognitions()
. Мой подход дает нам более тонкий контроль, потому что служба имеет знания уровня абстракции базы данных, где, как сущности не должны.
Я уверен, что на практике больше болей, которые я не перечислял здесь.
Какие конкретные преимущества существуют в подходах Мартина, которые могут убедить меня использовать образец модели данных данных?
Ответы
Ответ 1
Что касается вашего первого момента, вы должны использовать инъекцию зависимостей при создании экземпляра объекта Product. Конструкция графа объекта является полнофункциональной ответственностью и не должна смешиваться с вашей бизнес-логикой (принцип единой ответственности).
Что касается второго момента, то особенности вашего поставщика должны быть скрыты за вашим уровнем доступа к данным, а ваш DAO или репозиторий должны возвращать объекты в соответствии с вашими потребностями.
Альтернатива для вашей озабоченности по поводу жадной загрузки продукта s (при ситуации, в которой отношения друг к другу) заключается в том, чтобы Продукт DAO вводился в объект Контракт. При таком подходе вы можете получить связанный с контрактом продукт, связанный с контрактом, когда это необходимо (возможно, на геттере, который также можно использовать внутри).
Конечно, идеального решения не существует, и всегда будут компромиссы. Ваша работа в качестве архитектора для оценки подхода, который лучше подходит для вашего приложения.
В моем личном опыте я заметил, что слишком много полагаться на классы обслуживания, как правило, порождает гигантские классы, которые не имеют четко определенной ответственности и обычно слишком трудны для тестирования.
Таким образом, преимущества использования подхода "Модель домена" - четкое разделение проблем и повышенная тестируемость.
Наконец, вам не нужно использовать "чистый" подход к модели домена. Предполагается, что модель домена и уровень обслуживания будут использоваться вместе.
Объекты модели домена охватывают поведение, попадающее в их границы, и логика покрытия уровня обслуживания не принадлежит ни одному объекту домена.
Некоторые дополнительные ссылки вы можете найти интересными
Разработка и развитие домена на практике - интересная статья о DDD
Инъекция зависимостей, шаблоны проектирования с использованием Spring и Guice - отличная книга по инъекции зависимостей
Привет,
Эммануэль Луис Ларигет Бельтрам
Ответ 2
Модель домена представляет собой объект, а также поведение лучше, чем анемичное. Потому что поведение связано с ним. Основным примером является dog
может bark
, breathe
и eat
. В слое "Сервис" модель расширяется с помощью BarkHandler
и BreatheHandler
.
Доменный подход к модели основан на шаблоне проектирования UML. Мой предыдущий ответ здесь. Для подхода к моделированию аномальных доменов (уровень обслуживания) сложно сделать UML-диаграмму (диаграмму классов), и даже если вы смогли ее создать, она официально не принимается, поэтому люди будут иметь другую интерпретацию.
С точки зрения дизайна, уровень обслуживания слишком "independent
" или разделен. Если посмотреть на модель анемичного домена class
, вы не можете найти поведение (например, сохранение), связанное с моделью домена. Вам нужно найти весь проект, чтобы найти конкретное поведение для модели домена. Пока в богатой доменной модели вы знаете следы поведения внутри самой модели домена.
Богатая модель домена имеет улучшенный модификатор доступа (открытый, закрытый, защищенный) для своих свойств. А также видимость собственности. Например, если вы хотите изменить статус после отправки, вы можете заставить свойство получить доступ к public
, но установить доступ к protected
. На уровне обслуживания вам необходимо сделать доступ к набору public
или обмануть его с помощью internal protected
и заставить отправителя напрямую изменить свойство с помощью internal access
. Но это сложная задача.
Но богатая модель домена не обладает гибкостью, поскольку anemic domain model
имеет. Вы не можете добавлять поведение к модели без изменения класса модели домена, если вы не используете наследование. Хотя в модели анемичного домена вы даже можете менять ее на уровне времени выполнения.