一、问题引出
业务场景:消费者在图书商城购买图书,下单后需要在支付页面显示订单优惠后的价格。具体优惠规则如下:
规则编号 | 规则触发条件 | 优惠金额 |
---|---|---|
1 | 总价在100元以下 | 0 |
2 | 总价在100元到200元 | 20元 |
3 | 总价在200元到300元 | 50元 |
4 | 总价在300元以上 | 100元 |
【思考】:如何实现上述业务逻辑呢?
最容易想到的就是使用分支判断(if-else)来实现,伪代码如下:
//
if (sum < 100) {
return 0;
} else if (sum >= 100 && sum < 200){
return 20;
} else if (sum >= 200 && sum < 300) {
return 50;
} else {
return 100;
}
通过上面伪代码可以看出,业务规则是通过java代码实现。这种实现方式存在如下问题:
- 硬编码实现业务规则难以维护
- 硬编码实现业务规则难以应对变化
- 业务规则发生变化需要修改代码,重启服务后才能生效
面对此类业务场景,如何实现能比较好的应用规则的增加、修改和删除呢?
答:使用规则引擎!
二、规则引擎概述
2.1 什么是规则引擎
-
规则引擎,全称为业务规则管理系统(Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模板编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。
-
规则引擎不是一个具体的技术框架,而是一类系统。目前市面上的规则引擎产品有:drools、VisualRules、iLog等。
规则引擎实现了将业务决策从应用代码中分离出来,接收数据输入、解释业务规则,并根据业务规则做出业务决策 。规则引擎其实就是一个输入输出平台,上述购书满减场景使用规则引擎后效果如下:
系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理(规则管理后台),比如查询、添加、更新、统计、提交业务规则等。业务规则被加载到规则引擎中供应用系统调用。
2.2 使用规则引擎的优势
1、业务规则与系统代码分离,实现业务规则的集中管理
2、可以动态修改业务规则,从而快速响应需求变更
3、规则引擎是相对独立的,只关心业务规则
4、减少了硬编码业务规则的成本和风险
2.3 规则引擎适用场景
1、活动系统----满减、打折、加价购
三、Drools介绍
drools是一款由JBoss组织提供的基于Java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。
drools官网地址:drools.org/
drools源码下载地址:github.com/kiegroup/dr...
drools API开发步骤如下:
Drools开发实现(案例:消费者购买图书满减优惠)
1、引入依赖
xml
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.23.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.drools/drools-compiler -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.23.0.Final</version>
</dependency>
2、配置kmodule文件
在resources下创建META-INF文件夹,并且创建文件kmodule.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="rules">
<ksession name="all-rules"/>
</kbase>
</kmodule>
3、规则文件drl
在resources下创建rules文件夹,并创建规则文件。
规则文件如下:
less
//图书优惠规则
package rules.book
import com.example.droolsdemo.model.Order
//规则一:所购图书总价在100元以下的没有优惠
rule "book_discount_1"
when
$order:Order(originalPrice < 100)
then
$order.setRealPrice($order.getOriginalPrice());
System.out.println("成功匹配到规则一:所购图书总价在100元以下的没有优惠");
end
//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
when
$order:Order(originalPrice < 200 && originalPrice >= 100)
then
$order.setRealPrice($order.getOriginalPrice() - 20);
System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end
//规则三:所购图书总价在200到300元的优惠50元
rule "book_discount_3"
when
$order:Order(originalPrice <= 300 && originalPrice >= 200)
then
$order.setRealPrice($order.getOriginalPrice() - 50);
System.out.println("成功匹配到规则三:所购图书总价在200到300元的优惠50元");
end
//规则四:所购图书总价在300元以上的优惠100元
rule "book_discount_4"
when
$order:Order(originalPrice >= 300)
then
$order.setRealPrice($order.getOriginalPrice() - 100);
System.out.println("成功匹配到规则四:所购图书总价在300元以上的优惠100元");
end
实体类Order
kotlin
@Data
public class Order {
private Double originalPrice; //初始价格
private Double realPrice;//实际价格
}
4、测试方法
@Test
public void test() {
KieServices kieServices = KieServices.Factory.get();
KieContainer container = kieServices.getKieClasspathContainer();
//会话对象,用于和规则引擎交互
KieSession kieSession = container.newKieSession("all-rules");
//构造订单对象,设置原始价格,由规则引擎根据优惠规则计算优惠后的价格
Order order = new Order();
order.setOriginalPrice(210D);
//将数据提供给规则引擎,规则引擎会根据提供的数据进行规则匹配
kieSession.insert(order);
//激活规则引擎,如果规则匹配成功则执行规则
kieSession.fireAllRules();
//关闭会话
kieSession.dispose();
System.out.println("优惠前原始价格:" + order.getOriginalPrice() +",优惠后价格:" + order.getRealPrice());
}
测试结果: