【问题标题】:Rich domain model. Anti anemic domain model丰富的领域模型。抗贫血领域模型
【发布时间】:2014-01-05 17:10:36
【问题描述】:

很多讨论,比如thisthis,都使用富域模型

还有2 strong reason about amenic,比如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);

【问题讨论】:

  • 你问这是否是有效的 C# 代码?或者如果它比其他一些选项更可取?第一个问题的答案可以通过编译来测试。第二个问题的答案相当主观。
  • 也许这是 CodeReview 堆栈交换的问题。

标签: c# dependency-injection domain-driven-design domain-model anemic-domain-model


【解决方案1】:

如果你读过 DDD,你会发现 Repository 是 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】:

    听起来您的域中缺少一个概念。我会考虑引入某种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 一样,只有您的领域专家才能告诉您事情应该如何进行。

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

    【讨论】:

    • 首先,暴露 IEnumerable 是危险的,因为它有机会从数据库中提取所有产品。其次,IStoreInventory 的实现方式将变为普通存储库。所以和我的建议没有太大区别。
    • @Euphoric 我不认为StoreInventory 是一个存储库,我会让它本身成为一个一流的域实体,可能是 Store 聚合中的一个值对象。跨度>
    • “首先,暴露 IEnumerable 是危险的,因为它有可能从 DB 中提取所有产品。” 你在那里做了一大堆假设。首先,您假设该类完全连接到数据库,但事实并非如此。即使是这样,您也假设它使用的是实体框架、LinqSQL、NHibernate 或类似的东西。很多假设,没有一个是正确的。
    • “IStoreInventory 的实现方式将变成普通存储库” 一点也不,StoreInventory 将是Store 聚合中的值对象。因此,您将有一个 StoreRepository 来获取 Store 对象及其库存。
    • 它怎么可能是一个值对象,当它不包含任何属性时,“数据”被计算出来,它是一个接口,其具体实现存在于域之外(很可能作为数据的一部分-接入层)。此外,假设它是一个值对象,则不应将其作为参数传递,而应将其与订单关联。此外,您编写的代码将枚举所有产品并假设所有产品都在数据库中,您只需将所有产品拉入内存。
    猜你喜欢
    • 2010-12-20
    • 2020-01-29
    • 2012-02-04
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    相关资源
    最近更新 更多