今天放福利干货, 由于接触到了遇到了很多关于匹配条件判断的业务场景和需求,很多人可能不假思索的就直接干if-else,可能对代码有点追求的上了层次干策略模式,噼噼啪啪绞尽脑汁设计了一啪优雅牛逼的代码接口和实现,其实做过风控系统的同学们应该对规则引擎都不陌生,可以执行百度,规则引擎有好多,传统的我曾经用过的和感觉最容易上手的当属drools了,今天就干他,分享一下
直接开干
普通规则写法
先来常常鲜,堆叠式的规则写法,将所有的判断条件全部写一个规则,重复累赘
package rules;import com.example.drools.Fd.domain.TradeRecordimport java.math.BigDecimalimport org.slf4j.LoggerFactoryglobal org.slf4j.Logger loggerrule "Between3And12" when trd:TradeRecord(getFqNum() >=3 && getFqNum() < 12) then trd.setFee(new BigDecimal("0.05").multiply(trd.getAmount())); logger = LoggerFactory.getLogger("Drools-Between3And12"); logger.info("命中费率规则 :12期以上24期以内");endrule "Between12And24" when trd:TradeRecord(getFqNum() >= 12 && getFqNum() < 24) then trd.setFee(new BigDecimal("0.25").multiply(trd.getAmount())); logger = LoggerFactory.getLogger("Drools-Between12And24"); logger.info("命中费率规则 :12期以上24期以内");end
今天来个进阶的,首先编写一段规则模板,对我又在用模板方式
模板脚本:
这是一个根据交易分期数来匹配对应的期数费率区间,其实延伸开来,例如价格区间优化折扣、等这种带区间的需求都可以这样去实现,动态,易于维护,逻辑简单清晰易懂
package rules;dialect "java"import java.math.BigDecimalimport com.example.drools.Fd.domain.TradeRecordimport org.slf4j.LoggerFactoryglobal com.example.drools.Fd.domain.Fenqi fqsglobal org.slf4j.Logger loggerrule "BetweenMinAndMax" when trd:TradeRecord(getFqNum() >= fqs.getMin() && getFqNum() < fqs.getMax()) then trd.setFee(new BigDecimal(fqs.getRadio()).multiply(trd.getAmount())); logger = LoggerFactory.getLogger("Drools-BetweenMinAndMax"); logger.info("命中费率规则 : {} 期以上(包含),{} 期以内",fqs.getMin(),fqs.getMax());end
规则获取参数
- 可以使用global关键字将java参数定义成一个全局变量参数,在整个规则中都能使用到
- 使用 session.setGlobal("fqs",fenqishu) 传递全局参数
- 传参,使用session.insert(tradeRecord),规则中就像java代码一样丝滑
java执行代码:
简单模拟
- 一笔交易事实,100元的交易分了6期
- 3期到12期之间执行的费率是0.25%
- 命中规则,并之间计算分期费用,规则结果返回费用结果
public void getOutRuleFiles() throws IOException { KieServices kieServices = KieServices.Factory.get(); KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); File[] ruleFiles = Paths.get("d://temp/rules//").toFile().listFiles(); for (File file : ruleFiles) { kieFileSystem.write(ResourceFactory.newFileResource(file)); } KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll(); KieContainer kContainer = kieServices.newKieContainer(kieBuilder.getKieModule().getReleaseId()); KieBase kieBase = kContainer.getKieBase(); KieSession session = kieBase.newKieSession(); //交易事实 TradeRecord tradeRecord = new TradeRecord(); tradeRecord.setAmount(new BigDecimal(100)); tradeRecord.setFqNum(6); tradeRecord.setMerchantName("删古"); session.insert(tradeRecord); //条件事实 Fenqi fenqishu = new Fenqi(); fenqishu.setMax(12); fenqishu.setMin(3); fenqishu.setRadio(0.25); session.setGlobal("fqs",fenqishu); session.fireAllRules(); session.dispose(); System.out.println("命中规则计费结果:"+tradeRecord.getFee()); }
工程结构:spring-boot
pom依赖
总结
其实drools不是什么新技术,很老的东西了,但是网上很多用法是直接将规则写到工程本身的/main/resources/目录下,试想一下,如果这样就不太方便了,如果规则随时需要变动,那不是要重新打包吗,所以结合实践,把规则拿出来放在指定外部目录中是非常有必要的,就几行代码就能解决多少if判断,将规则做成API,也能实现解耦,技术不复杂,思路和解决方案更重要,希望对路过的朋友有所帮助。
版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除