irpas技术客

Java规则引擎easy-rules_syrain丶华思雨_java 规则引擎

未知 5658

Java规则引擎easy-rules

首先以通俗的语言表达何为规则引擎: 一段代码:

public class FizzBuzz { public static void main(String[] args) { for(int i = 1; i <= 100; i++) { if (((i % 5) == 0) && ((i % 7) == 0)){ System.out.print("能被5和7同时整除的数字"); } else { System.out.print("i"); } } } }

上述代码中循环了100次,从1开始循环+1. 如果当前数字能被5、7整除。打印:能被5和7同时整除的数字 其余的数字依次打印出来。

其实上面例子中的如果就是我们希望的规则,由此可见当我们业务上遇到较为复杂多样的规则的时候,代码中会出现满篇的if–else。降低代码的易读性、增加代码行数,后期修改规则繁复等等的弊端都体现出来。因此我们用到了规则引擎,也就是今天的主人公——easy-rules。

Easy Rules是一个简单但功能强大的Java规则引擎,提供以下特性: 轻量级框架和易于学习的API基于POJO的开发支持从原始规则创建组合规则支持通过表达式(如MVEL,SPEL和JEXL)定义规则

先从一段源码来了解:

package org.jeasy.rules.api; public interface Rule extends Comparable<Rule> { private final Condition condition; private final List<Action> actions; //name:规则命名(空间中的唯一规则名称) default String getName() { return "rule"; } //规则的简要描述 default String getDescription() { return "description"; } //规则的优先级 1>2>3>4..以此类推 default int getPriority() { return 2147483646; } /** * 此方法封装了规则的条件。 * @return 如果根据提供的事实可以应用规则,则为true,否则为false */ public boolean evaluate(Facts facts) { return this.condition.evaluate(facts); } /** * 此方法封装了规则的操作。 * @throws 如果在执行操作期间发生错误,则抛出异常 */ public void execute(Facts facts) throws Exception { Iterator var2 = this.actions.iterator(); while(var2.hasNext()) { Action action = (Action)var2.next(); action.execute(facts); } } }

evaluate()方法封装了必须为true才能触发规则的条件。 execute()方法封装了在满足规则条件时应该执行的操作。 条件和操作由Condition和Action接口表示。 总结来说,我们可以通过定义Condition来判断是否执行此规则,通过Action来决定执行什么样的规则。

上面大概讲述了一下rule的基本结构,下面我们来探讨下究竟如何使用:

注解方式:

完整的示例需要几个东西要讲一下,大家耐心看完:

第一点:Easy Rules提供了@Rule注解,可以将POJO转换为规则 @Rule(name = "myrule", description = "这是一个规则的描述", priority = 1) public class MyRule { // @Condition注解用来标记是否符合规则的方法,这个方法必须是public; //可以有一个或多个带@Fact注解的参数,并返回一个boolean类型。 //只有一个方法可以用@Condition注解标记。 @Condition public boolean when(@Fact("fact") fact) { return true; } //@Action注解用来标记执行操作的方法,规则可以有多个操作。可以使用order属性以指定的顺序执行操作 @Action(order = 1) public void then(Facts facts) throws Exception { // 规则为true时的操作1 } @Action(order = 2) public void finally() throws Exception { // 规则为true时的操作2 } }

上面代码中,我们自己通过注解的方式先定义了一个规则,以及规则是否执行的条件,执行的内容。

第二点:上面代码中的@Fact注解是什么意思呢?

源码:

public class Fact<T> { private final String name; private final T value; }

实际上是一个事实,name代表了在事实中的命名,value则是实际要传递的参数。

Facts API表示一组事实 所以在同一空间内,fact的name不可重复。

//新建一组事实 Facts facts = new Facts(); facts.put("isFive", "5"); 第三点:建立规则引擎 //引擎被创建 默认的应用规则 RulesEngine rulesEngine = new DefaultRulesEngine(); // or 自定义应用规则 RulesEngine rulesEngine = new InferenceRulesEngine(); //执行。 rulesEngine.fire(rules, facts);

规则引擎参数 Easy Rules引擎可以配置以下参数:

rulePriorityThreshold:当优先级超过指定的阈值时,跳过余下的规则。skipOnFirstAppliedRule:当一个规则成功应用时,跳过余下的规则。skipOnFirstFailedRule:当一个规则失败时,跳过余下的规则。skipOnFirstNonTriggeredRule:当一个规则未触发时,跳过余下的规则。

示例:

RulesEngineParameters parameters = new RulesEngineParameters() .rulePriorityThreshold(10) .skipOnFirstAppliedRule(true) .skipOnFirstFailedRule(true) .skipOnFirstNonTriggeredRule(true); RulesEngine rulesEngine = new DefaultRulesEngine(parameters); 简单了解了以上三点,便可以进行一个简单的程序了:

按照我们开篇的例子来说

循环100次,从1开始循环+1. 如果当前数字能被5、7整除。打印:能被5和7同时整除的数字 其余的数字依次打印出来。

把上述规则建立起来 ↓

/** 当前数字能被5、7整除。打印:能被5和7同时整除的数字 **/ @Rule public class FiveSevenRule { @Condition public boolean isFiveSevenRule (@Fact("number") Integer number) { return number % 5 == 0 && number % 7 == 0; } @Action public void printInput(@Fact("number") Integer number) { System.out.print("能被5和7同时整除的数字"); } @Priority public int getPriority() { return 1; } } /** 打印其余数字 **/ @Rule public class OrtherNumRule { @Condition public boolean isFiveSevenRule (@Fact("number") Integer number) { return true; } @Action public void printInput(@Fact("number") Integer number) { System.out.print(number); } @Priority public int getPriority() { return 2; } }

使用:

public class FizzBuzzWithEasyRules { public static void main(String[] args) { // 创建规则引擎 RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true); RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters); // 创建规则 Rules rules = new Rules(); rules.register(new FiveSevenRule()); rules.register(new OrtherNumRule()); // 触发规则 Facts facts = new Facts(); for (int i = 1; i <= 100; i++) { facts.put("number", i); fizzBuzzEngine.fire(rules, facts); } } }

结果: 由此可见,我们的规则运行起来了。注意:我在创建规则引擎的时候,用了.skipOnFirstAppliedRule(true);也就是说按规则顺序执行后,当规则1完成后,跳过规则2。所以34后面不会再打印35,而直接接了36.

以上便是简单的规则使用。 未完待续…


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #JAVA #规则引擎 #class #FizzBuzz #PUBLIC