5

我在很多地方读到过,DDD 中的一个重要要求是对存储库有一个有界合同:

findByName(string name)
findByEmail(string email)
etc.

并且不提供通用查询接口:

findBySpecification(Specification spec)

我确实理解为什么这很重要:能够模拟存储库以进行测试,或更改底层持久性框架。

虽然在整个应用程序中执行此规则并不难,但在为用户提供“高级搜索”表单时,我不知道如何执行它。

假设我有一个表单,它允许按关键字日期作者等搜索博客文章。

这些标准可以自由组合,我显然无法为每个用例提供方法:

findByKeyword(string keyword)
findByDateRange(Date from, Date to)
findByKeywordAndDateRange(string keyword, Date from, Date to)
findByDateRangeAndAuthor(Date from, Date to, User author)
etc.

我错过了什么还是规则的例外之一?

4

3 回答 3

2

将规范作为参数传递给存储库没有任何问题。这实际上是解决存储库接口上的方法爆炸的一个很好的方法。看看这个答案。对于“高级搜索”场景,“过滤器”可能比“规范”更合适。我认为这段代码不会违反任何 DDD 准则:

Filter filter = new FilterBuilder()
    .WithinDateRange(dateRange)
    .IncludingKeywords("politics", "news")
    .ByAuthor("John Smith")
    .Build();

blogs.FindByFilter(filter);

请注意,创建过滤器的代码可以存在于域之外。因为它不会违反任何域规则。如果有“匿名作者发布的博客需要版主批准”之类的规则怎么办?虽然它可以用 Filter 来表达,但这样做会外化一段业务逻辑。将此规则放入域代码并拥有专用的存储库方法会更有意义,例如:

blogs.RequireModeratorAttention();
于 2011-09-05T02:27:31.933 回答
1

存储库模式有两个主要好处:

  1. 它将您的应用程序与持久层和惯用语分离。
  2. 它将数据访问集中并限制到定义良好且易于理解的领域段(存储库中的数据访问方法具有明确定义的结果并且可合理测试)。

如果您使用持久层提供的规范模式的一个实例(例如 NHibernate Criteria),您就否定了好处之一。完全使用规范模式(即使是你自己滚动的)会削弱第二个的好处。

话虽这么说,在某些情况下,例如搜索界面,规范是必要的——只要确保并推出你自己的。

于 2011-09-05T03:08:19.367 回答
1

虽然在整个应用程序中执行此规则并不难,但在为用户提供“高级搜索”表单时,我不知道如何执行它。

实际上,如果您只需要一个搜索表单,您就不必支付所有这些抽象的成本。存储库(至少在 DDD 的上下文中)旨在从业务逻辑(应用层)中抽象出持久性框架的细微差别。

如果你有一个更改用户地址的命令,最好有一个带有 FindUserById 方法的存储库,而不是在应用层中有一些神奇的 Hibernate 代码。有两个原因

  • 您可能希望使用模拟的持久层(存储库)来测试应用程序层
  • 应用层是你关心的东西,因为它是业务逻辑

您不需要所有这些来获取 UI 的一些数据。我建议使用甚至可能存在于 UI 层中的专门的“Finder”类。它们既可以在抽象的“规范”上运行,也可以(甚至更好)在裸 Hibernate(或您最喜欢的 ORM)上运行。我在这里写了一篇关于这种方法的博客文章。

于 2011-09-05T05:40:17.923 回答