должна ли доменная модель поддерживать себя согласованной при использовании событий? - PullRequest
1 голос
/ 10 августа 2011

Я работаю над приложением, в котором мы пытаемся использовать модель предметной области. Идея состоит в том, чтобы сохранить бизнес-логику внутри объектов в доменной модели. Теперь многое делается для объектов, подписывающихся на связанные объекты, чтобы реагировать на изменения в них. Это делается через PropertyChanged и CollectionChanged. Эта работа хорошо, за исключением следующего:

Сложные действия: где много изменений следует обрабатывать как группа (а не отдельные изменения свойства / коллекции). Должен ли я / как я могу «строить» транзакции?

Постоянство: я использую NHibernate для постоянства, и это также использует установщики открытых свойств классов. Когда NHibernate попадает в свойство, выполняется много бизнес-логики (что кажется ненужным). Должен ли я использовать собственные сеттеры для NHibernate?

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

Вот примерная проблема (извините за дерьмовый инструмент, который я использую):

enter image description here

Вы можете видеть, как контейнер Project my и объекты под ним реагируют друг на друга, подписавшись. Теперь изменения в сети выполняются через NetworkEditor, но этот редактор не знает о NetworkData. Эти данные могут даже иногда быть определены в другой сборке. Поток идет от пользователя-> NetworkEditor-> Network-> NetworkData и всех других заинтересованных объектов. Это не похоже на масштаб.

1 Ответ

2 голосов
/ 10 августа 2011

Я боюсь, что комбинация событий DDD и PropertyChanged / CollactionChanged теперь может быть лучшей идеей. Проблема заключается в том, что если вы основываете свою логику на этих событиях, управлять сложностью крайне сложно, поскольку один PropertyChanged ведет к другому, а другой - и вскоре вы теряете контроль.

Другая причина, по которой события ProportyChanged и DDD не совсем подходят, заключается в том, что в DDD каждая бизнес-операция должна быть максимально явной. Имейте в виду, что DDD должен внести технические вещи в мир бизнеса, а не наоборот. И на основании PropertyChanged / CollectionChanged, кажется, не очень явно.

В DDD главная цель состоит в том, чтобы поддерживать согласованность внутри агрегата, другими словами, вам необходимо смоделировать агрегат таким образом, чтобы любая операция, которую вы вызываете агрегат, была действительной и согласованной (если операция, конечно, завершается успешно).

Если вы строите свою модель правильно, вам не нужно беспокоиться о «построении» транзакции - операция над агрегатом должна быть самой транзакцией.

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

Пример:

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

    public class CustomerOrder
    {
        public List<Payment> Payments { get; }
        public Balance BalanceForOrder { get; }

        public void SetPaymentAsReceived(Guid paymentId)
        {
            Payments.First(p => p.PaymentId == paymentId).Status = PaymentStatus.Received;
            RecalculateBalance();
        }
    }

Возможно, вы заметили, что мы пересчитываем баланс одного заказа, а не баланс всего клиента - и в большинстве случаев это нормально, так как клиент принадлежит к другому агрегату, и его баланс можно просто запросить при необходимости. Это как раз та часть, которая демонстрирует эту «согласованность только внутри агрегата» - на данный момент нам нет дела до других агрегатов, мы имеем дело только с одним заказом. Если это не подходит для требований, то домен смоделирован неправильно.

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

Если вы посмотрите на приведенный выше пример, вы увидите, что нет необходимости «строить» транзакцию - вся транзакция находится в методе SetPaymentAsReceived. В большинстве случаев одно действие пользователя должно приводить к одному конкретному методу на объекте без агрегата - этот метод явно относится к бизнес-операции (конечно, этот метод может вызывать другие методы).

Что касается событий в DDD, существует концепция событий домена, однако они не связаны напрямую с техническими событиями PropertyChanged / CollectionChanged. События домена указывают на бизнес-операции (транзакции), которые были выполнены агрегатом.

В целом кажется, что нажатие всей логики в модели предметной области делает модель предметной области довольно сложная

Конечно, он делает то, что предполагается использовать для сценариев со сложной бизнес-логикой. Однако, если домен смоделирован правильно, эту сложность легко контролировать и контролировать, и это одно из преимуществ DDD.

Добавлено после предоставления примера:

Хорошо, а как насчет создания агрегатного корня с именем Project - когда вы создаете агрегатный корень из репозитория, вы можете заполнить его NetworkData, и операция может выглядеть следующим образом:

    public class Project
    {
        protected List<Network> networks;
        protected List<NetworkData> networkDatas;

        public void Mutate(string someKindOfNetworkId, object someParam)
        {
            var network = networks.First(n => n.Id == someKindOfNetworkId);
            var someResult = network.DoSomething(someParam);

            networkDatas.Where(d => d.NetworkId == someKindOfNetworkId)
                .ToList()
                .ForEach(d => d.DoSomething(someResult, someParam));
        }
    }

NetworkEditor не будет работать в сети напрямую, а через Project с использованием NetworkId.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...