我在许多地方读到,DDD中的一个重要要求是为Repository有一个有界的合同:
findByName(string name)
findByEmail(string email)
etc.而不提供通用查询接口:
findBySpecification(Specification spec)我理解为什么这很重要:能够在测试中模拟Repository,或者更改底层的持久性框架。
虽然这条规则在整个应用程序中并不难执行,但当涉及到向用户提供“高级搜索”表单时,我想不出如何执行它。
假设我有一个表单,允许通过关键字、date、author等搜索博客文章。
这些标准可以自由组合,我显然不能为每个用例提供一个方法:
findByKeyword(string keyword)
findByDateRange(Date from, Date to)
findByKeywordAndDateRange(string keyword, Date from, Date to)
findByDateRangeAndAuthor(Date from, Date to, User author)
etc.我是遗漏了什么,还是规则的例外之一?
发布于 2011-09-05 02:27:31
将规格说明作为参数传递给存储库没有什么问题。这实际上是处理存储库接口上的方法爆炸的一种非常好的方法。看看这个回答。“过滤器”可能比“高级搜索”场景中的“规范”更合适。我认为这个代码不会违反任何DDD准则:
Filter filter = new FilterBuilder()
.WithinDateRange(dateRange)
.IncludingKeywords("politics", "news")
.ByAuthor("John Smith")
.Build();
blogs.FindByFilter(filter);请注意,创建筛选器的代码可以驻留在域之外。因为它不会违反任何域规则。如果有这样的规则:“匿名作者发布的博客应该由版主批准”呢?虽然它可以用过滤器表示,但这样做会使业务逻辑外化。将此规则放入域代码并有一个专门的存储库方法将更有意义,如:
blogs.RequireModeratorAttention();发布于 2011-09-05 03:08:19
储存库模式有两个主要好处:
如果您使用持久层提供的规范模式的实例(例如NHibernate标准),那么您就否定了它的好处。使用规范模式(甚至是你自己的一种模式)会削弱第二种模式的好处。
尽管如此,在某些情况下,如搜索接口,规范是必要的-只是确保并滚动您自己的。
发布于 2011-09-05 05:40:17
虽然这条规则在整个应用程序中并不难执行,但当涉及到向用户提供“高级搜索”表单时,我想不出如何执行它。
实际上,如果您只需要一张搜索表单,您就不必支付所有这些抽象的费用。存储库(至少在DDD上下文中)是为了从业务逻辑(应用层)抽象持久性框架的细微差别而设计的。
如果您有一个更改用户地址的命令,那么与其在应用程序层中使用一些神奇的Hibernate代码,不如使用FindUserById方法创建一个存储库。这有两个原因
您不需要所有这些来获取UI的一些数据。我建议使用专门的“Finder”类,这些类甚至可能存在于UI层中。它们既可以在抽象的“规范”上运行,也可以(更好地)运行于裸Hibernate (或您最喜欢的ORM)上。我写了一篇关于这种方法这里的博客文章。
https://stackoverflow.com/questions/7303116
复制相似问题