本文我们来介绍一下规格模式(Specification Pattern)
规格模式是一种常用的软件设计模式,其目的将业务规则封装成可重用的对象,并且能够动态地组合这些规则,以实现更复杂的业务逻辑。
意图
规格模式(Specification Pattern)是一种行为设计模式,它的意图是将一个业务规则表示为一个对象,并且将多个规则组合成更为复杂的规则。该模式可以将规则的表示与规则的实现分离,从而实现可扩展性、可维护性和可重用性。
结构
规格模式的结构大致如下:
这里涉及到的参与者有如下几种:
Specification(规则接口)
包含一个用于检验对象是否符合规则的方法,如isSatisfiedBy
AbstractSpecification(抽象规则)
包含一个抽象的isSatisfiedBy方法,以及and、or和not方法,适合于与AND、或OR、非NOT场景的支持。
LeafSpecification(具体规则)
实现规则接口的isSatisfiedBy方法
在给出示例之前,我们先来看一个筛选的例子。
在有些场景中,需要对一个集合的对象进行过滤。比如,我有很多本书,想要知道价格为50元以上且出版社包含“工业”字样的书籍有哪些。简单实现一下:
Book类
简单过滤的基本逻辑:
那么问题来了,如果筛选条件很多,if条件的判断就变得很不好维护。
接下来,我们使用规格模式的写法来完成,看看效果。
示例一、条件筛选
规格接口
抽象规格
AND、OR和Not规格
具体书本规格
Client端
条件的筛选我们可以通过如下方式来做
完整Client代码
运行结果
这样一个简单的规格模式示例就完成了。
当然,为了方便多个规则的组装,我们也可以写一个规格Builder,然后通过addSpecification()方法来增加规格。如:
规格Builder
Client客户端
同样,执行之后也能看到过滤的后的结果。
如果使用JDK 1.8及以上版本,使用Predicate甚至不需要写任何的Specifation即可完成。使用Predicate结合stream可以轻松使用筛选。
Predicate接口组成
查看Predicate源码,我们可以看到,其定义了一个test方法,以及and、or和negative方法,和Specification类似。
示例二、JPA使用规格模式构建查询语句
我们知道,Spring Data JPA是Spring框架(Spring Boot)中提供的非常有用的模块,可以以最小的工作量访问持久层并使用JPA减少大量样板代码。
它允许使用不同的方法创建查询,例如:
除了这些常见的方法之外,还有一种方法可以使用Spring JPA已提供的Specification Pattern动态创建查询,并利用JPA Criteria API的优势。
有时候,针对一个对象需要应用不同的查询条件,需要为每种可能的组合创建大量不同的方法。Specification Pattern源自Eric Evans的《领域驱动设计》一书中介绍的概念。它提供了一种设计模式,允许我们将搜索条件与执行搜索的对象分开。
注:也可以通过访问如下url地址https://martinfowler.com/apsupp/spec.pdf获取Evans和Martin Fowler所写的Specification文章。
让我们来看一个例子。
使用Spring Data JPA提供的Repository模式及其功能,通常会开始为应用程序和业务逻辑所需的每个不同查询添加新的方法定义。对于具有许多属性/字段的实体,Repository可能会以大量不同的查询组合方式结束,所有这些方法都在单独的方法中,因此我们的类会变得越来越庞大,包含数十个甚至更多。如:
从生产力的角度来看,这种情况是可以接受的,作为开发人员,我可以在几秒钟内创建一个方法,通过某些特定字段过滤数据库并返回Java中的值,我们作为开发人员将专注于功能和业务逻辑。
然而,从可读性和可维护性的角度来看,这种情况,一个包含几十个方法甚至更多方法的类简直就是一场噩梦。由于Spring Data JPA的命名约定,我们可能会有一些难以理解的方法名。
规格模式是一种很好的解决方案,它可以在代码中增强可读性和可维护性,同时最大限度地减少样板代码,并且重复使用现有代码。
在Spring Data JPA中使用规格模式
Spring已经提供了Specification接口来实现它,并使不同的规格在我们的代码库中可重用。
Specification
JpaSpecicationExecutor<T>
实现JpaSpecificationExecutor接口后,Repository类会新增一些方法,用于使用Specification进行查询。这些方法将替代我们之前需要的大量的方法来满足每个不同的条件组合。
在使用 JPA 的 Repository 中使用规格模式
这样,我们就可以轻松地创建可重用和可组合的查询规格,并将它们用于不同的查询。代码也变得清晰明了。
优缺点
优点
缺点
规格模式和组合模式
规格模式和组合模式是两个不同的设计模式,它们虽然有些相似之处,但并不是一个的扩展。
组合模式是一种结构型模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端可以统一处理单个对象和对象组合,从而使得代码更加简洁、灵活。
规格模式则是一种行为型模式,它将业务规则封装为一个规格对象,用于判断给定对象是否满足特定的规则。规格模式可以将多个规格对象进行组合,从而得到更复杂的规则。在规格模式中,客户端通常需要将业务规则和对象进行分离,从而使得业务规则的变化不会影响到对象的实现。
其它
规格模式是领域驱动设计(DDD)中的一种模式。在DDD中,规格模式被用于描述领域中的特定概念,例如产品规格、订单规格等等。规格模式可以让我们通过将业务逻辑与数据访问逻辑分离来更好地实现领域驱动设计的目标。
规格模式可以使用的场景可以有:
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。