商城系统,消费赠送积分,规则如下:
100元以下,不加分
100元~500元 加100分
500元~1000元 加500分
1000元以上 加1000分
if…else:
package com.example.droolstest;
/**
* @author 木子的昼夜编程
*/
public class Test01 {
public static void main(String[] args) {
// 充值金额
int amont = 100;
// 获取原积分
int score = 0;
if (amont <= 100) {
score = score + 0;
}else if (amont >100 && amont<=500) {
score = score + 100;
} else if (amont > 500 && amont<= 1000){
score = score + 500;
} else if (amont > 1000) {
score = score + 1000;
}
System.out.println(score);
}
}
策略模式:
讲实话,如果不用配置文件进行配置,策略模式跟if…else没有什么区别(我个人认为)
package com.example.droolstest;
/**
* @author 木子的昼夜编程
*/
public class Test01 {
public static void main(String[] args) {
// 充值金额
int amont = 100;
// 获取原积分
int score = 0;
Strategy strategy = null;
if (amont <= 100) {
strategy = new Strategy01();
}else if (amont >100 && amont<=500) {
strategy = new Strategy02();
} else if (amont > 500 && amont<= 1000){
strategy = new Strategy03();
} else if (amont > 1000) {
strategy = new Strategy04();
}
Context context = new Context(strategy);
System.out.println(context.addScore(score));
}
}
class Context{
Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
int addScore(int score){
return strategy.addScore(score);
}
}
interface Strategy{
int addScore(int score);
}
class Strategy01 implements Strategy{
@Override
public int addScore(int score) {
return score + 0;
}
}
class Strategy02 implements Strategy{
@Override
public int addScore(int score) {
return score + 100;
}
}
class Strategy03 implements Strategy{
@Override
public int addScore(int score) {
return score + 500;
}
}
class Strategy04 implements Strategy{
@Override
public int addScore(int score) {
return score + 100;
}
}
如果是一个固定的类型,我们可以用Map<>,映射一个对应关系出来,也就是把if…else用key-value实现
但是范围的话… 我想想能不能简单化一点。
绞尽脑汁想到了一个(其实是百度找的)好像简单了点儿,但是貌似以后修改改动不必if…else简单。
package com.example.droolstest;
import java.util.ArrayList;
import java.util.List;
/**
* @author 木子的昼夜编程
*/
public class Test01 {
public static void main(String[] args) {
// 充值金额
int amont = 340;
// 获取原积分
int score = 0;
Strategy strategy = WhichStrategy.getStrategy(amont);
Context context = new Context(strategy);
System.out.println(context.addScore(score));
}
}
class Context{
Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
int addScore(int score){
return strategy.addScore(score);
}
}
class WhichStrategy{
int start;
int end;
Strategy strategy;
public WhichStrategy(int start, int end, Strategy strategy) {
this.start = start;
this.end = end;
this.strategy = strategy;
}
static List<WhichStrategy> allStrategy = new ArrayList<>();
static {
allStrategy.add(new WhichStrategy(0,100, new Strategy01()));
allStrategy.add(new WhichStrategy(100,500, new Strategy02()));
allStrategy.add(new WhichStrategy(500,1000, new Strategy03()));
allStrategy.add(new WhichStrategy(1000,Integer.MAX_VALUE, new Strategy04()));
}
public static Strategy getStrategy(int amont){
if (amont <0 ) {
throw new RuntimeException("闹着玩呢?充值负数?");
}
for (int i = 0; i < allStrategy.size(); i++) {
WhichStrategy whichStrategy= allStrategy.get(i);
if (whichStrategy.start < amont && whichStrategy.end >= amont) {
return whichStrategy.strategy;
}
}
throw new RuntimeException("没有匹配到策略!");
}
}
interface Strategy{
int addScore(int score);
}
class Strategy01 implements Strategy{
@Override
public int addScore(int score) {
return score + 0;
}
}
class Strategy02 implements Strategy{
@Override
public int addScore(int score) {
return score + 100;
}
}
class Strategy03 implements Strategy{
@Override
public int addScore(int score) {
return score + 500;
}
}
class Strategy04 implements Strategy{
@Override
public int addScore(int score) {
return score + 100;
}
}
其实如果需求很固定,那就很简单了,我们if…else能解决99%的业务。
如果需求变更呢?积分层次增加?积分比例调整?
我们把这些范围对应的积分配置化?放数据库?放配置中心?
问题:
我们要简化if…else,让业务和数据库逻辑分离
我们要用更方便、更便于维护的程序来实现这些功能。而且修改了逻辑后,程序不用重启。
规则引擎由推理引擎发展而来的,是一种嵌入在应用程序的组件,实现了将业务决策从应用程序代码中分离出来(也就是新增和删除if…else的动作不再由修改代码实现,可以由配置实现),并使用预定的语义模块编写业务决策。接收数据输入,解释业务规则,并根据业务规则作出业务决策。
注意:规则引擎不是某一个具体的技术框架,而是只一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:drools、visualRules、iLog、Easy Ruls、RuleBook、Openl-Tablets等
我们一般在营销系统、crm系统、库存、风控、采购、促销平台等用的比较多。
比如贷款发放、票价、折扣(打折、满减、加价购等)、价格、风控规则等各种业务规则。
在AI领域,产生式系统是一个很重要的理论,产生式推理分为正向推理和逆向推理产生式,其规则的一般形式是:
If条件Then操作。rete算法是实现产生式系统中正向推理的高效模式匹配算法,通过形成一个rete网络进行模式匹配,利用基于规则的系统的时间冗余性和结构相似性特征,提高系统模式匹配效率。
正向推理:
正向推理也叫演绎法,我们经常看军旅电视剧和刑侦电视剧都有推演这么一说,就是通过已经发生的事情,想想后边的事情,比如杀人犯A,连续3年在中秋节杀人,那我们有理由推理出,今年中秋节,他还会出来杀人。
正向推理由事实驱动,从一个初始的事实出发,不断地应用规则得出结论。首先在候选队列中选择一条规则作为启用规则进行推理,记录其结论作为下一步推理的证据。如果重复这个过程,直到再无可用规则可被选用或者得到了所要求的解位置。
反向推理:
反向推理也叫归纳法,我们假设今年中秋会出现月饼涨价,我们需要支撑这个推论的证据是去年、前年、大前年、大大前年连续4年都是中秋月饼涨价,然后我们搜集证据,发现确实如此,那我们就可以证明,今年月饼会涨价。
反向推理由目标驱动,首先提出某个假设,然后寻找支持该假设的证据,若所需的证据都能找到,说明原假设是正确的,若无论如何都找不到所需证据,则说明原假设不成立,此时需要另做新的假设。
我们不深究这个算法的实际实现数学公式,我们只做简单了解即可。(当然如果有能力你去研究一下原理也是非常ok的),我们知道我们写了那么多规则文件,最后怎么快速匹配,快速执行,快速出结果的,是用到了rete算法。
在网上看到一段话:
rete算法最初是由卡内基美隆大学Charles L.Forgy博士在1974年发表的论文中阐述的算法(好家伙,比我还早出现将近20年),该算法提供了专家系统的一个高效实现。自rete算法提出以后,他就被用在一些大型的规则系统中。
rete在拉丁语中被译为“net”,也就是网络的意思,rete匹配算法是一种进行大规模集合和大量对象集合间比较的高效算法,通过网络少选的方法找出所有匹配的各个模式的对象和规则。
其核心算法是将分离的匹配项根据内容动态构造匹配树(我们听到树这个词,就应该意识到是为了加快速度的),以达到显著降低计算量的效果。rete算法可以被分为两部分:规则编译和规则执行。当rete算法进行事实的断言时,包含三个阶段:匹配、选择和执行,称做:match-select-act cycle
https://github.com/kiegroup/drools
drools具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验已编码的规则是否执行了所需的业务规则。其前身是Codehaus的一个开源项目叫Drools,后被纳入JBoos门下,更名为Jboss Rules,成为了JBoos应用服务器的规则引擎。
Drools被分为两个主要部分:编译和运行。编译是将规则描述文件按照ANTLR 3语法进行解析,对语法进行正确性检查(跟我们java代码编译一个道理),然后生成一种中间结构“descr”(可以类比我们的.class文件),descr用AST来描述规则。目前,Drools支持4中规则描述文件:drl、xls、brl和dsl文件。其中的描述文件是drl文件和xls文件,xls文件更易于维护,更直观,更容易被业务人员所理解(毕竟业务人员更喜欢操作Excel文档)。运行时是将AST传到PackageBuilder,由PackageBuilder产生rulebase,它包含了一个或多个Package对象。
lombok 这个跟drools没直接关系,但是用了都说好。
drools-core、drools-compiler 这俩是主要的jar包
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.droolsgroupId>
<artifactId>drools-coreartifactId>
<version>7.17.0.Finalversion>
dependency>
<dependency>
<groupId>org.droolsgroupId>
<artifactId>drools-compilerartifactId>
<version>7.17.0.Finalversion>
dependency>
dependencies>
com.example.droolstest.entity.Order.java
package com.example.droolstest.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author 木子的昼夜编程
*/
@Data
@Accessors(chain = true)
public class Order {
/**
* 订单原价金额
*/
private int price;
/**
*积分
*/
private int score;
}
com.example.droolstest.entity.User.java
package com.example.droolstest.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author 木子的昼夜编程
*/
@Data
@Accessors(chain = true)
public class User {
/**
* 姓名
*/
private String name;
}
resources/rules/order-rules.drl
package rules;
// 引入实体
import com.example.droolstest.entity.Order;
import com.example.droolstest.entity.User;
// 编写规则
rule "add0"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price <= 100)
then
$order.setScore(0);
update($order)
end
rule "add100"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 100 && price <= 500)
then
$order.setScore(100);
update($order)
end
rule "add500"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 500 && price <= 1000)
then
$order.setScore(500);
update($order)
end
rule "add1000"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 1000)
then
$order.setScore(1000);
update($order)
end
DroolsTestApplicationTests
package com.example.droolstest;
import com.example.droolstest.entity.Order;
import com.example.droolstest.entity.User;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.junit.jupiter.api.Test;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.springframework.boot.test.context.SpringBootTest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class DroolsTestApplicationTests {
// 测试
@Test
public void droolsOrderTest() throws Exception {
KieSession kieSession = getKieSession();
List<Order> orderList = getInitData();
for (Order order: orderList) {
// 1-规则引擎处理逻辑
kieSession.insert(order);
kieSession.fireAllRules();
// 2-执行完规则后, 执行相关的业务逻辑 我们就简单输出
addScore(order);
}
kieSession.dispose();
}
private static void addScore(Order o){
System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
}
// 获取session 线程不安全 所以需要每次使用的时候获取新的
public KieSession getKieSession(){
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
// 这里可以从各个地方获取配置文件 比如网络 字节数组
kbuilder.add(ResourceFactory.newClassPathResource("rules/order-rules.drl"), ResourceType.DRL);
//BUILD RULEBASE
InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addPackages( kbuilder.getKnowledgePackages() );
//NEW WORKING MEMORY
final KieSession session = kbase.newKieSession();
return session;
}
// 初始化数据(模拟数据库获取的数据)
private static List<Order> getInitData(){
List<Order> orderList = new ArrayList<>();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// 张三买东西
{
Order order = new Order();
order.setPrice(80);
User user = new User();
user.setName("张三");
order.setUser(user);
order.setScore(111);
orderList.add(order);
}
// 李四买东西
{
Order order = new Order();
order.setPrice(200);
User user = new User();
user.setName("李四");
order.setUser(user);
orderList.add(order);
}
// 王五买东西
{
Order order = new Order();
order.setPrice(800);
User user = new User();
user.setName("王五");
order.setUser(user);
orderList.add(order);
}
// 孙子买东西
{
Order order = new Order();
order.setPrice(1500);
User user = new User();
user.setName("孙子");
order.setUser(user);
orderList.add(order);
}
return orderList;
}
}
输出结果:
