DDD:存储库合约
我在很多地方读到,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.
我是否遗漏了某些内容,或者它是规则的例外情况之一?
I've read in various places that one important requirement in DDD is to have a bounded contract for the Repository:
findByName(string name)
findByEmail(string email)
etc.
And not provide a generic query interface:
findBySpecification(Specification spec)
I do understand why this is important: to be able to mock the Repository for tests, or change the underlying persistence framework.
While this rule is not that hard to enforce throughout the application, I can't figure out how to enforce it when it comes to provide the user with an "advanced search" form.
Let's say I have a form which allows to search blog posts by keyword, by date, by author, etc.
These criteria being freely combinable, I obviously can't provide a method for each use case:
findByKeyword(string keyword)
findByDateRange(Date from, Date to)
findByKeywordAndDateRange(string keyword, Date from, Date to)
findByDateRangeAndAuthor(Date from, Date to, User author)
etc.
Am I missing something or is it one of the exceptions to the rule?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将 规范 作为参数传递给存储库没有任何问题。这实际上是解决存储库接口上方法爆炸的一个非常好的方法。看看这个答案。对于“高级搜索”场景,“过滤器”可能比“规范”更合适。我认为这段代码不会违反任何 DDD 准则:
请注意,创建过滤器的代码可以位于域之外。因为它不会违反任何域规则。如果存在诸如“匿名作者发布的博客应得到版主批准”之类的规则怎么办?虽然可以用Filter来表达,但这样做会将业务逻辑具体化。将此规则放入域代码中并拥有专用的存储库方法会更有意义,例如:
There is nothing wrong with passing Specification as a parameter to a repository. This is actually a very good way of tackling method explosion on the repository interface. Take a look at this answer. 'Filter' maybe more appropriate name than 'Specification' for the 'advanced search' scenario. I think this code will not violate any DDD guidelines:
Note that the code that creates the filter can live outside of domain. Because it will not violate any domain rules. What if there is a rule like "Blogs posted by Anonymous author should be approved by moderator"? Although it can be expressed with Filter, doing so will externalize piece of business logic. It will make more sense to put this rule into domain code and have a dedicated repository method like:
实际上,如果您只需要一个搜索表单,则无需支付所有这些抽象的成本。存储库(至少在 DDD 的上下文中)旨在从业务逻辑(应用程序层)中抽象出持久性框架的细微差别。
如果您有一个更改用户地址的命令,那么最好有一个带有 FindUserById 方法的存储库,而不是在应用程序层中拥有一些神奇的 Hibernate 代码。有两个原因
(repositories)mocked
因为它是业务逻辑
您不需要所有这些来获取 UI 的一些数据。我建议使用专门的“Finder”类,这些类甚至可能位于 UI 层中。它们可以在抽象“规范”上运行,也可以在裸露的 Hibernate(或您最喜欢的 ORM)上运行(甚至更好)。我在此处写了一篇关于此方法的博客文章。
Actually, you don't have to pay the cost of all these abstractions if all you need is a search form. Repository (in context of DDD at least) was designed to abstract the nuances of persistence framework from the business logic (application layer).
If you have a command that changes user's address, it's better to have a repository with FindUserById method than to have some magic Hibernate code in the app layer. There are two reasons for this
(repositories) mocked
because it's business logic
You don't need all of these to just get some data for the UI. I would suggest using specialized 'Finder' classes that may even live in the UI layer. They can operate either on abstract 'specification' or (even better) on bare Hibernate (or your favourite ORM). I've written a blog post about this approach here.
存储库模式有两个主要优点:
如果您使用持久层提供的规范模式的实例(例如 NHibernate Criteria),您就否定了好处之一。完全使用规范模式(即使是您自己推出的规范模式)会削弱第二点的好处。
话虽如此,在某些情况下(例如搜索界面),规范是必要的 - 只需确保并推出您自己的规范即可。
The Repository pattern has two main benefits:
If you use an instance of the specification pattern provided by your persistence layer (e.g. NHibernate Criteria), you negate benefit one. Using the specification pattern at all (even one you roll yourself) waters down the benefit of number two.
That being said, in some situations such as search interfaces, specification is necessary - just make sure and roll your own.