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