DDD,处理依赖项

时间:2010-02-09 04:27:38

标签: inversion-of-control domain-driven-design

无聊介绍:

我知道 - DDD与技术无关。正如我所看到的 - DDD就是要与产品所有者一起创造无处不在的语言,并以如此简单和结构化的方式将其反映到代码中,以至于它不会被误解或丢失。

但是这里出现了一个悖论 - 为了摆脱领域模型中的应用技术方面,它至少从设计角度来看是技术性的。

上次我试图关注DDD - 它最终将域对象之外的整个逻辑变成了“魔术”服务和贫血领域模型。

我已经学会了一些新的忍者技巧,并想知道我这次是否可以处理歌利亚。


问题:

class store : aggregateRoot { 
  products;
  addProduct(product){
    if (new FreshSpecification.IsSatisfiedBy(product))
      products.add(product);
  }
}

class product : entity {
  productType;
  date producedOn;
}

class productTypeValidityTerm : aggregateRoot {
  productType;
  days;
}

FreshSpecification应该指明产品是否有异味。为了做到这一点 - 它应该检查产品的类型,找到产品新鲜的天数并将其与producedOn进行比较。很简单。

但是问题出现了 - productTypeValidityTermproductType应该由客户端管理。他应该能够自由地添加/修改它们。因为我无法直接从产品遍历productTypeValidityTerm,所以我需要以productType的方式查询它们。

以前 - 我会创建类似ProductService的东西,它通过构造函数接收必要的存储库,查询术语,执行一些额外的伏都教并返回布尔值(使相关逻辑远离对象本身并散布它知道在哪里)。 / p>

我认为做这样的事可能是可以接受的:

addProduct(product, productTypeValidityTermRepository){...}

但话又说回来 - 我无法自由地从多个规范中编写规范,这是他们的主要优势之一。

所以 - 问题是,在哪里这样做?商店如何知道条款?

1 个答案:

答案 0 :(得分:2)

存在过度简化事物的风险:为什么不说明Product是否是产品“知道”的新鲜事物? Store(或任何其他类型的相关对象)不应该知道如何确定产品是否仍然新鲜;换句话说,freshSpecificationproductTypeValidityTerm之类的事实甚至不应该为Store所知,它应该只检查Product.IsFresh(或者可能是其他一些对齐的名称)更好地利用现实世界,例如ShouldbeSoldByExpiresAfter等。然后,产品可以通过注入存储库依赖性来了解如何实际检索protductTypeValidityTerm

在我看来,您正在外化行为,这应该是您的域聚合/实体固有的行为,最终导致(再次)成为贫血领域模型。

当然,在一个更复杂的情况下,新鲜度取决于环境(例如,预算商店中可接受的价格不值得在高级商店出售),您需要将整个行为外部化,这两者都来自产品并从商店,并创建一个不同的类型来模拟这种特殊的行为。

在评论后添加

我提到的简单场景沿着这些方向做了一些事情:制作Product聚合的FreshSpec部分,它允许ProductRepository(这里注入构造函数)到(懒惰)在需要时加载它。

public class Product {
  public ProductType ProductType { get; set; }
  public DateTime ProducedOn { get; set; }
  private FreshSpecification FreshSpecification { get; set; }
  public Product(IProductRepository productRepository) { }

  public bool IsFresh() {
    return FreshSpecification
      .IsSatisfiedBy(ProductType, ProducedOn);
  }
}

商店不知道这些内部结构:它关心的是产品是否是新鲜的:

public class Store {
  private List<Product> Products = new List<Product>();
  public void AddProduct(Product product) {
    if (product.IsFresh()) {
      Products.Add(product);
    }
  }
}