Где мы проводим грань между делегированием и инкапсуляцией бизнес-логики? Мне кажется, что чем больше мы делегируем, тем более анемичным мы становимся. Тем не менее, делегирование также способствует повторному использованию и принципу DRY. Так что уместно делегировать и что должно остаться в наших моделях доменов?
Возьмите следующие проблемы в качестве примеров:
Авторизация . Должен ли объект домена отвечать за поддержание своих правил контроля доступа (таких как свойство CanEdit) или он должен быть делегирован другому компоненту / услуге, единолично отвечающему за управление доступом, например, IAuthorizationService.CanEdit (object)? Или это должно быть сочетание двух? Возможно, у объекта домена есть свойство CanEdit, которое делегирует внутреннему IAuthorizationService для выполнения фактической работы?
Проверка . То же обсуждение, что и выше, относится к валидации. Кто поддерживает правила и кто отвечает за их оценку? С одной стороны, состояние объекта должно принадлежать этому объекту, а валидность - это состояние, но мы не хотим переписывать код, используемый для оценки правил для каждого объекта домена. Мы могли бы использовать наследование в этом случае ...
Создание объекта . Фабричный класс в сравнении с фабричными методами против «обновления» экземпляра. Если мы используем отдельный класс фабрики, мы можем изолировать и инкапсулировать логику создания, но за счет открытия состояния нашего объекта для фабрики. Этим можно управлять, если наш уровень домена находится в отдельной сборке, предоставляя внутренний конструктор, используемый фабрикой, но это становится проблемой, если существует несколько шаблонов создания. И если все, что делает фабрика, - это вызывать правильного конструктора, какой смысл иметь фабрику?
Методы фабрики в классе устраняют проблему с открытием внутреннего состояния объекта, но поскольку они статичны, мы не можем нарушать зависимости посредством внедрения фабричного интерфейса, как мы можем с отдельным фабричным классом.
Постоянство . Можно утверждать, что, если наш объект домена собирается предоставлять CanEdit, делегируя ответственность за проверку прав доступа другой стороне (IAuthorizationService), почему бы не использовать метод Save для нашего объекта домена, который делает то же самое? Это позволило бы нам оценить внутреннее состояние объекта, чтобы определить, можно ли выполнить операцию, не нарушая инкапсуляцию. Конечно, это требует, чтобы мы внедрили экземпляр репозитория в наш объект домена, что немного пахнет для меня, так что мы вместо этого вызываем событие домена и позволяем обработчику выполнять операцию персистентности?
Видишь, куда я иду с этим?
У Рокфорда Лотки есть отличная дискуссия о причинах, по которым он выбрал маршрут Class-in-Charge для своей платформы CSLA, и у меня есть немного истории с этой платформой, и я могу увидеть его идею о том, что бизнес-объекты во многом параллельны объектам домена. Но, пытаясь стать более приверженными хорошим идеалам DDD, мне интересно, когда сотрудничество становится слишком много.
Если я получу сервис IAuthorizationService, IValidator, IFactory и IRepository для моего совокупного корня, что останется? Достаточно ли наличия метода Publish, который изменяет состояние объекта с «Черновик» на «Опубликованный», чтобы считать класс неанемичным доменным объектом?
Твои мысли?