由DDD之父 Eric Evans 和OO之父 Martin Fowler定义的规范(Specification也称规格模式)模式article 越来越受到广泛应用,本文介绍如何使用JavaEE 持久层规范JPA实现规格模式,其实现思想也适合其他持久层框架。案例源码见GitHub。
在这个文章中,我们将使用以下POLL类作为创建Specification为例实体。它代表了民意调查,有一个开始和结束日期。在这两个日期之间的时间内用户可以在不同的选择之间投票表决Poll,投票Poll可以在管理员的结束日期尚未到达前锁定。在这种情况下,一个锁日期将被设置。
1 |
|
现在我们有两个约束:
- 一个投票poll如果满足startDate < now < endDate,那表示它在进行中。
- 一个投票poll如果超过100个投票但是没有锁定,表示它很流行。
我们可以通过在POLL投票添加适当的方法如:poll.isCurrentlyRunning(),另外,我们可以使用一个服务方法pollService.isCurrentlyRunning(进行轮询)。然而,我们也希望能够查询数据库获得所有当前正在运行的民意调查。因此,我们可以添加一个DAO或储存repository库的方法类似pollRepository.findAllCurrentlyRunningPolls()。
如果我们想结合上述两个约束查询,例如我们想在数据库中查询当前正在运行的所有流行的调查名单?这时Specification模式派上用场。当使用Specification模式时,我们将业务规则转换为额外的类称为Specification。
创建Specification接口和抽象类如下:
1 | public interface Specification { |
specification的核心是isSatisfiedBy()方法,用于检查一个对象是否满足规范规格要求。
toPredicate()是一个附加的方法,我们在案例中使用它返回一个约束。
javax.persistence.criteria.Predicate 实例,它能被用于查询一个数据库。
检查一个poll是否正在运行的规范实现如下:
1 | public class IsCurrentlyRunning extends AbstractSpecification { |
检查一个投票是否流行的代码如下:
1 | public class IsPopular extends AbstractSpecification { |
使用代码:
1 | boolean isPopular = new IsPopular().isSatisfiedBy(poll);boolean isCurrentlyRunning = new IsCurrentlyRunning().isSatisfiedBy(poll); |
为了查询数据库,我们需要继承扩展DAO/Repository来支持规范:
1 | public class PollRepository { |
我们使用 AbstractSpecification的getType() 方法 创建CriteriaQuery 和 Root 实例. getType()返回的是一个 AbstractSpecification泛型,可以由子类定义. 对于流行IsPopular 且正在进行IsCurrentlyRunning它返回一个Poll class。
如果没有 getType()我们必须在每个规范的 toPredicate() 中实现创建 CriteriaQuery 和 Root实例。它只是减少烦人代码的帮助者。
使用代码:
1 | List popularPolls = pollRepository.findAllBySpecification(new IsPopular()); |
下面问题是如何结合这两个规范,我们如何查询数据库所有流行且还在进行的投票呢?
使用组合模式实现组合规范模式。名称为AndSpecification:
1 | public class AndSpecification extends AbstractSpecification { |
使用代码:
1 | Specification popularAndRunning = new AndSpecification<>(new IsPopular(), new IsCurrentlyRunning()); |
为了提供可读性,我们增加and方法到规范接口
1 | public interface Specification { |
使用代码:
1 | Specification popularAndRunning = new IsPopular().and(new IsCurrentlyRunning()); |
转载自https://www.jdon.com/idea/javaee7/specification-pattern-with-jpa.html