В шаблонах архитектуры корпоративных приложений Мартин Фаулер рассказывает о двух шаблонах для организации Domain Logic: Модель домена и Уровень обслуживания. Шаблон модели домена - это подход "чистого ООП", где модели (те объекты, которые, вероятно, просматриваются из базы данных с использованием ORM) содержат бизнес-логику (хотя, вероятно, только делегирование логики в другом классе).
Шаблон Service Layer похож на шаблон модели домена, но с тонким слоем перед ним, содержащим бизнес-операции, которые могут быть выполнены. В MVC контроллер будет в основном взаимодействовать с уровнем обслуживания. Я считаю, что большинство хорошо продуманных веб-приложений MVC используют этот шаблон.
Теперь, на мой вопрос. Мартин предполагает, что подход "Модель домена" является более объектно-ориентированным подходом и поэтому лучше. По моему опыту, это очень сложно (см.: Невозможно) реализовать на практике.
Возьмем пример, приведенный на первой диаграмме выше. Существует два "объекта" 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()
. Мой подход дает нам более тонкий контроль, потому что служба имеет знания уровня абстракции базы данных, где, как сущности не должны.
Я уверен, что на практике больше болей, которые я не перечислял здесь.
Какие конкретные преимущества существуют в подходах Мартина, которые могут убедить меня использовать образец модели данных данных?