DDD - Доступ к репозиториям от сущностей, бис - PullRequest
1 голос
/ 03 сентября 2011

Я задал предыдущий вопрос в прошлом месяце о том, должен ли объект получить доступ к репозиторию, и, хотя большинство людей считает, что не должны, я должен признать, что мне трудно

У меня есть сценарий использования, для которого я действительно не могу придумать какой-либо ( разумный ) способ сделать логику без внедрения Репозитория в мою сущность:

У нас есть Store, которому присваивается Zone (город, район, ... - определяется пользователем).Чтобы уменьшить нагрузку на сотрудника, отвечающего за добавление хранилищ в базу данных, и для обеспечения согласованности, мы не просим его выбирать зону, в которой он хочет добавить хранилище.Он просто увеличивает масштаб карты, нажимает, чтобы точно определить местоположение Магазина, и сохраняет.Затем приложение должно найти наиболее подходящую зону для этого местоположения.

То, что у меня сейчас есть, выглядит примерно так:

class Store
{
    protected Zone zone;
    protected Point location;
    protected ZoneRepository zoneRepository;

    public void setLocation(Point location)
    {
        Zone matchingZone = this.zoneRepository.findByLocation(location);
        if (matchingZone == null) {
            throw new ApplicationException(
                "The store location must be within a zone boundary");
        }
        this.location = location;
        this.zone = matchingZone;
    }
}

Есть ли у вас альтернатива solid , котораяподдержал бы общепринятое мнение, что этот дизайн по своей сути плох?

Ответы [ 4 ]

3 голосов
/ 03 сентября 2011

Не обязательно говорить, что этот дизайн плохой.Это просто вызывает вопросы.В большинстве случаев нет необходимости использовать хранилище изнутри сущности.Поиск магазина в собственной зоне, основанной на географической точке, кажется немного странным.Не похоже, что эта ответственность принадлежит Магазину.

Всегда ли требуется точка?Что если пользователь захочет выбрать зону из списка «Последние 5 зон»?Или из Страны / Города выпадающих?Или из текстового поля поиска?Там нет необходимости для точки в этих случаях.Требование точки и репозитория выглядит как адаптация модели домена к модели пользовательского интерфейса.

Если вам действительно нужна точка для каждого отдельного Магазина, вам может не понадобиться поле Зоны в одно и то же время.Что если вы будете искать Зону Магазина динамически, только когда вам это нужно?Использование самой современной базы данных Point-to-Zone.

Также, если в вашем классе Store есть 5 или 6 методов, и только одному из них необходимо поле zoneRepository, тогда класс не очень связный .

1 голос
/ 03 сентября 2011

Из приведенного вами описания кажется, что Point на самом деле не является частью вашего Ubiquitous Language - Зона есть. Вы не устанавливаете точку для хранения - вы назначаете ей зону. Другими словами, подпись этой операции не должна быть setLocation(Point location) - она ​​должна быть assignZone(Zone locationZone). Перевод между точкой, выбранной пользователем, и зоной должен произойти до того, как будет выполнена операция модели домена. Вот как я это смоделирую.

Пример добавлен после комментариев (C #, если вы не возражаете - и показывает только концепцию). Код предполагает командный подход к выполнению действий пользователя - так я обычно это делаю, но может быть даже Application Service или Controller, в зависимости от структуры вашего приложения.

    public class StoreLocationHandler : Handles<LocateStoreCommand>
    {
        public void Handle(LocationStoreCommand command)
        {
            // Location contains coordinates as well as zone info and can be obtained only via LocationService
            Location location = LocationService.IdentifyZone(command.Coordinates); 

            Store store = StoreRepository.Get(command.StoreId);

            store.AssignLocation(location);

            // persist changes - either by Unit of Work or Repository
        }
    }

Дело в том, что вам не нужно создавать все внутри сущностей вашего домена - Zone, похоже, является Value Object с точки зрения Store. Кроме того, дальнейшее разделение этих двух концепций может привести к дополнительным возможностям, таким как идентификация зоны не в сети, а посредством какого-то фонового процесса (ради производительности или масштабируемости). Кроме того, на мой взгляд, он подходит лучше, учитывая принцип Dependency Injection .

В конце концов, домен не заботится о том, как создается или восстанавливается зона, он заботится об ассоциации между Магазином, его местоположением и зоной, в которую он попадает. Почему он должен отвечать за перевод между точкой и зоной? По крайней мере, так я это вижу.

1 голос
/ 03 сентября 2011

Я использую тот же подход и, как вы, не смог убедиться, что это плохой дизайн.ОДНАКО, у меня есть интерфейсы к моим репозиториям, поэтому я не использую конкретные реализации ZoneRepository, так как это может привести к затруднениям, и в зависимости от контекста невозможно проверить и смоделировать его.

Другой момент, например, как @Самич сказал, что звучит неплохо, если взять знания о поиске зоны на основе точки из объекта Store, так как позже вы можете использовать этот метод в другом месте.Если вы воспользуетесь сервисом для Зон, вы сможете централизовать свой код и избежать избыточности.

1 голос
/ 03 сентября 2011

С точки зрения DDD для поиска по пунктам у вас должен быть отдельный сервис для него, например LocationService, который будет инкапсулировать ваш репозиторий внутри. И этот сервис не должен ничего знать о User хранилище сущности и особенно никогда не включать хранилище в сущность.

...