Богатая модель предметной области. Модель антианемического домена

Много обсуждений, например this и this, используйте RICH DOMAIN MODEL

и есть 2 веских довода в пользу аменика, например 1 и 3:

Теперь предположим, что мне нужно убедиться, что мне нужно подтвердить, что продукт существует в инвентаре, и выдать исключение, если это не так.

поэтому возникает вопрос: если нам не нужно, чтобы объект зависел от ISomeRepository подобной службы, можем ли мы просто сделать это:

public void Order.AddOrderLine(IEnumerable<Product> products, Product product)
{
    if(!prosucts.Contains(product))
         throw new AddProductException

    OrderLines.Add(new OrderLine(product));
}

и назовите это так:

Order.AddOrderLine(ISomeRepository.GetAll(), product);

comment
Вы спрашиваете, допустим ли это код C #? Или, если это предпочтительнее каких-то других вариантов? Ответ на первый вопрос можно проверить, составив его. Ответ на второй вопрос довольно субъективен.   -  person Mark Hildreth    schedule 17.12.2013
comment
Возможно, это вопрос к обмену стеками CodeReview.   -  person MattDavey    schedule 17.12.2013


Ответы (2)


Похоже, здесь в вашем домене отсутствует концепция. Я бы подумал о введении какой-то StoreInventory сущности, такой, чтобы продукты перемещались из инвентаря в заказ (во многих областях торговли это называется «сбором»).

interface StoreInventory
{
    IEnumerable<Product> AvailableProducts { get; }
    Product PickProduct(guid productId); // This doesn't have to be an Id, it could be some other key or a specification.
}

void Order.AddOrderLine(StoreInventory inventory, Product product)
{
    if (!inventory.AvailableProducts.Contains(product.Id))
        throw new AddProductException();

    var item = inventory.Pick(product);
    OrderLines.Add(new OrderLine(item);
}

Мне это кажется более близким к реальности. Но, как всегда в DDD, только эксперты в вашей предметной области могут сказать вам, как все должно идти.

Это также кажется более расширяемым в будущем, например, с помощью этой модели будет легко ввести несколько магазинов - каждый со своим собственным инвентарем.

person MattDavey    schedule 17.12.2013
comment
Во-первых, открывать IEnumerable опасно, потому что есть шанс получить все продукты из БД. Во-вторых, способ реализации IStoreInventory превратится в обычный репозиторий. Так что это не сильно отличается от того, что я предлагал. - person Euphoric; 17.12.2013
comment
@Euphoric Я бы не стал рассматривать StoreInventory как репозиторий, я бы сделал его самостоятельным объектом домена первого класса, возможно, объектом значения в агрегате Store. - person MattDavey; 18.12.2013
comment
Во-первых, раскрытие IEnumerable опасно, потому что у него есть шанс получить все продукты из БД. Вы делаете здесь целый ряд предположений. Во-первых, вы предполагаете, что класс вообще подключен к базе данных, а это не так. И даже если это так, вы предполагаете, что он использует Entity Framework, LinqSQL, NHibernate или что-то подобное. Множество предположений, ни одно из них не верное. - person MattDavey; 15.01.2014
comment
способ реализации IStoreInventory превратится в обычный репозиторий Вовсе нет, StoreInventory будет объектом значения в агрегате Store. Следовательно, у вас будет StoreRepository для получения Store объекта вместе с его инвентарем. - person MattDavey; 15.01.2014
comment
Как он может быть объектом значения, если он не содержит никаких атрибутов, данные вычисляются, и это интерфейс, конкретная реализация которого существует вне домена (скорее всего, как часть уровня доступа к данным). Кроме того, предполагая, что это объект значения, вы не должны передавать его в качестве параметра, но должны связать его с порядком. Кроме того, в написанном вами коде будут перечислены все продукты, и если все продукты находятся в базе данных, вы просто загрузили все продукты в память. - person Euphoric; 15.01.2014
comment
Я действительно не говорю о каком-то псевдо DDD поверх модели данных Entity Framework. Как я уже сказал, StoreInventory не имеет абсолютно никакого отношения к базе данных. На самом деле трудно понять, о чем я говорю, когда вы так зациклены на способе работы Entity Framework (который имеет очень мало общего с DDD). - person MattDavey; 16.01.2014
comment
Я говорю о том, что проверка того, доступен ли продукт, будет своего рода запросом к базе данных. Неважно, EF это или SQL. Вот почему он должен быть реализован как репозиторий. Это гораздо более безопасное предположение, чем предположение, что вы можете иметь все продукты в памяти, доступной через IEnumerable. - person Euphoric; 16.01.2014
comment
Вы снова делаете предположения, основываясь на одном очень наивном способе реализации DDD. Мой ответ не имеет никакого отношения к базе данных. проверка того, доступен ли продукт, будет своего рода запросом к базе данных неверно. он должен быть реализован как репозиторий. неверно. при условии, что у вас могут быть все продукты в памяти, доступной через IEnumerable. Вы можете, хотя вам это кажется невозможным, потому что EF не позволяет вам иметь концепцию ограниченных контекстов. А без ограниченного контекста вы вообще не выполняете DDD. - person MattDavey; 17.01.2014

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

public void Order.AddOrderLine(ISomeRepository repo, Product product)
{
    if(!repo.ProductExists(product))
         throw new AddProductException

    OrderLines.Add(new OrderLine(product));
}

// call it like
Order.AddOrderLine(someRepository, product);

Я думаю, проблема вашего заблуждения в том, что репозиторий, или, точнее, его абстракция, часто привязаны к самой персистентности. На самом деле это заблуждение, вызванное непониманием всей картины. Правильный репозиторий состоит из 2 частей: абстракции, обычно представленной интерфейсом, который определяет, какие операции требуются домену от персистентности. И конкретная реализация, которая реализует эти операции над используемой технологией сохранения.

person Euphoric    schedule 17.12.2013