C# 富域模型。抗贫血区域模型

C# 富域模型。抗贫血区域模型,c#,dependency-injection,domain-driven-design,domain-model,anemic-domain-model,C#,Dependency Injection,Domain Driven Design,Domain Model,Anemic Domain Model,许多讨论,如and,都与丰富的域模型相关 还有,像1和3: 现在让我们说,我需要确保我需要验证这一点 产品存在于库存中,如果不存在,则抛出异常 所以有一个问题:如果我们不需要像服务一样依赖于异构存储的对象,我们可以这样做吗: public void Order.AddOrderLine(IEnumerable<Product> products, Product product) { if(!prosucts.Contains(product)) throw

许多讨论,如and,都与丰富的域模型相关

还有,像1和3:

现在让我们说,我需要确保我需要验证这一点 产品存在于库存中,如果不存在,则抛出异常

所以有一个问题:如果我们不需要像服务一样依赖于
异构存储
的对象,我们可以这样做吗:

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

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

若您阅读了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);

我认为您困惑的问题在于存储库,或者更准确地说,它的抽象,常常与持久性本身联系在一起。这实际上是对整个模式的误解造成的误解。正确的存储库由两部分组成:抽象,通常由接口表示,它定义了域从持久性中需要什么样的操作。还有具体的实现,它通过使用持久性技术来实现这些操作。

听起来您的领域中缺少了一个概念。我会考虑引入某种
StoreInventory
实体,使产品从库存中移出并进入订单(在许多商业领域称为“拣货”)

接口存储目录
{
IEnumerable可用产品{get;}
Product PickProduct(guid productId);//这不必是一个Id,它可以是其他某个键或规范。
}
作废订单。添加订单行(仓库库存、产品)
{
如果(!inventory.AvailableProducts.Contains(product.Id))
抛出新的AddProductException();
var项目=存货、提货(产品);
订单行。添加(新订单行(项目);
}
在我看来,这似乎更符合现实。但和DDD一样,只有你的领域专家才能告诉你事情应该如何发展


这在未来似乎更具可扩展性,例如,使用这种模式,可以很容易地引入多个商店——每个商店都有自己的库存。

您是在问这是有效的C代码吗?还是它比其他一些选项更可取?第一个问题的答案可以通过编译来测试。第二个问题的答案是这是一个很主观的问题。这可能是CoDeVIEW栈交换的一个问题。首先,暴露iQueDead是危险的,因为它有可能从DB中拖拽所有的产品。第二,IStoreInventory的实现方式将变成正常的知识库。所以它和我建议的没有多大的差别。code>StoreInventory要成为一个存储库,我会让它本身成为一个一流的域实体,可能是存储聚合中的一个值对象。“首先,公开IEnumerable是危险的,因为它有可能从DB中提取所有产品。”你在这里做了一大堆假设。首先,你假设这个类与数据库连接,而事实并非如此。即使是这样,你也假设它使用实体框架、LinqSQL、NHibernate或类似的东西。很多假设,都不正确。“IStoreInventory的实现方式将转变为普通的存储库“完全不是,
StoreInventory
将是
Store
聚合中的一个值对象。因此,您将有一个
StoreRepository
来获取
Store
对象及其库存。当它不包含任何属性时,“数据”怎么可能是值对象?”它是一个接口,其具体实现存在于域之外(很可能作为数据访问层的一部分)。此外,假设它是一个值对象,则不应将其作为参数传递,而应将其与order关联。此外,您编写的代码将枚举所有产品,并且假设所有产品都在数据库中,您只需将所有产品拉入内存。
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);
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);
}