• java轻量级规则引擎easyrules使用介绍


    我们在写业务代码经常遇到需要一大堆if/else,会导致代码可读性大大降低,有没有一种方法可以避免代码中出现大量的判断语句呢?

    答案是用规则引擎,但是传统的规则引擎都比较重,比如开源的Drools,不适合在小需求中应用。最近在github上面看到一个傻瓜式的Java规则引擎Easy-Rules,这里结合自己写的demo介绍如何使用这个规则引擎,希望对大家有所帮助。

    easy-rules的特点

    1 轻量级类库和容易上手
    2 基于POJO的开发与注解的编程模型
    3 基于MVEL表达式的编程模型(适用于极简单的规则,一般不推荐)
    4 支持根据简单的规则创建组合规则
    5 方便且适用于java的抽象的业务模型规则
    特点

    概念

    了解规则引擎,我们先了解几个概念,如图所示

    我们看到

    1)facts表示当前被传入的key:value结构的参数

    2)rule就是一整个规则

    3)Condition就是rule的判断条件

    4)action就是满足Condition以后需要触发的动作

    那么整个逻辑就是,当一个facts参数对象传入的时候,遍历rules各个规则。每个规则进行规则的条件判断,如果满足条件,那么就触发执行相应的业务逻辑。

    其实总体逻辑依旧是一种类似if/else的概念

    它主要包括几个主要的类或接口:Rule,RulesEngine,RuleListener,Facts

    还有几个主要的注解:@Action,@Condition,@Fact,@Priority,@Rule

    maven依赖

     1    <dependency>
     2       <groupId>org.jeasy</groupId>
     3       <artifactId>easy-rules-core</artifactId>
     4       <version>3.3.0</version>
     5     </dependency>
     6     <dependency>
     7       <groupId>org.jeasy</groupId>
     8       <artifactId>easy-rules-mvel</artifactId>
     9       <version>3.3.0</version>
    10     </dependency>
    maven

    easy-rules的实现方式(2种)

    1. 实现Rule接口,并实现其evaluate和execute方法。
    2. 使用@Rule注解修饰POJO

    实战

    例1:基于POJO开发与注解的编程模型:判断1-50中,被3或者8整除的数

     编写规则POJO: 

     1 @Rule(name = "被3整除", description = "number如果被3整除,打印:number is three")
     2 public class ThreeRule {
     3   /**
     4    * Condition:条件判断注解:如果return true, 执行Action
     5    *
     6    * @param number
     7    * @return
     8    */
     9   @Condition
    10   public boolean isThree(@Fact("number") int number) {
    11     return number % 3 == 0;
    12   }
    13 
    14   /**
    15    * Action 执行方法注解
    16    *
    17    * @param number
    18    */
    19   @Action
    20   public void threeAction(@Fact("number") int number) {
    21     System.out.println(number + " is three");
    22   }
    23 
    24   /**
    25    * Priority:优先级注解:return 数值越小,优先级越高
    26    *
    27    * @return
    28    */
    29   @Priority
    30   public int getPriority() {
    31     return 1;
    32   }
    33 }
    规则1--被3整除
     1 @Rule(name = "被8整除")
     2 public class EightRule {
     3 
     4   /**
     5    * 条件
     6    *
     7    * @param number
     8    * @return
     9    */
    10   @Condition
    11   public boolean isEight(@Fact("number") int number) {
    12     return number % 8 == 0;
    13   }
    14 
    15   /**
    16    * 满足条件的动作
    17    *
    18    * @param number
    19    */
    20   @Action
    21   public void eightAction(@Fact("number") int number) {
    22     System.out.println(number + " is eight");
    23   }
    24 
    25   /**
    26    * 条件判断的优先级
    27    *
    28    * @return
    29    */
    30   @Priority
    31   public int getPriority() {
    32     return 2;
    33   }
    34 }
    规则2--被8整除
     1 @Rule(name = "被3和8同时整除", description = "这是一个组合规则")
     2 public class ThreeEightRuleUnitGroup extends UnitRuleGroup {
     3 
     4   public ThreeEightRuleUnitGroup(Object... rules) {
     5     for (Object rule : rules) {
     6       addRule(rule);
     7     }
     8   }
     9 
    10   @Override
    11   public int getPriority() {
    12     return 0;
    13   }
    14 }
    规则3--被3和8同时整除
     1 @Rule(name = "既不被3整除也不被8整除", description = "打印number自己")
     2 public class OtherRule { 
     3   @Condition
     4   public boolean isOther(@Fact("number") int number){
     5     return number % 3 != 0 || number % 8 != 0;
     6   }
     7 
     8   @Action
     9   public void printSelf(@Fact("number") int number){
    10     System.out.print(number);
    11   }
    12 
    13   @Priority
    14   public int getPriority(){
    15     return 3;
    16   }
    17 }
    规则4--既不被3整除也不被8整除
     1 public class ThreeEightRuleLauncher {
     2 
     3   public static void main(String[] args) {
     4     /**
     5      * 创建规则执行引擎
     6      * 注意: skipOnFirstAppliedRule意思是,只要匹配到第一条规则就跳过后面规则匹配
     7      */
     8     RulesEngineParameters parameters = new 
     9     RulesEngineParameters().skipOnFirstAppliedRule(true);
    10     RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
    11     //创建规则
    12     Rules rules = new Rules();
    13     rules.register(new EightRule());
    14     rules.register(new ThreeRule());
    15     rules.register(new ThreeEightRuleUnitGroup(new EightRule(), new ThreeRule()));
    16     rules.register(new OtherRule());
    17     Facts facts = new Facts();
    18     for (int i=1 ; i<=50 ; i++){
    19       //规则因素,对应的name,要和规则里面的@Fact 一致
    20       facts.put("number", i);
    21       //执行规则
    22       rulesEngine.fire(rules, facts);
    23       System.out.println();
    24     }
    25   }
    26 }
    执行规则

    例2:基于MVEL表达式的编程模型

    本例演示如何使用MVEL表达式定义规则,MVEL通过Easy-Rules MVEL模块提供。此模块包含使用MVEL定义规则的API。我们将在这里使用这些API,其目标是实现一个简单的商店应用程序,要求如下:禁止儿童购买酒精,成年人的最低法定年龄为18岁。 商店顾客由Person类定义:

     1 @Data
     2 @AllArgsConstructor
     3 @NoArgsConstructor
     4 public class Person {
     5   private String name;
     6 
     7   private boolean adult;
     8 
     9   private int age;
    10   //getter, setter 省略
    11 
    12 
    13   public Person(String name, int age) {
    14     this.name = name;
    15     this.age = age;
    16   }
    Person

    我们定义两个规则:

    • 规则1:可以更新Person实例,判断年龄是否大于18岁,并设置成人标志。
    • 规则2:判断此人是否为成年人,并拒绝儿童(即非成年人)购买酒精。

    显然,规则1的优先级要大于规则2,我们可以设置规则1的Priority为1,规则2的Priority为2,这样保证规则引擎在执行规则的时候,按优先级的顺序执行规则。

     Rule ageRule = new MVELRule()
            .name("age rule")
            .description("Check if person"s age is > 18 and marks the person as adult")
            .priority(1)
            .when("person.age > 18")
            .then("person.setAdult(true);");
    规则1
    1 规则2的定义,我们放到alcohol-rule.yml文件中
    2 
    3 name: "alcohol rule" 
    4 description: "children are not allowed to buy alcohol" 
    5 priority: 2 
    6 condition: "person.isAdult() == false" 
    7 actions: 
    8  - "System.out.println("Shop: Sorry, you are not allowed to buy alcohol");"
    规则2
     1 public class ShopLauncher {
     2   public static void main(String[] args) throws Exception {
     3     //创建一个Person实例(Fact)
     4     Person tom = new Person("Tom", 19);
     5     Facts facts = new Facts();
     6     facts.put("person", tom);
     7 
     8     //创建规则1
     9     Rule ageRule = new MVELRule()
    10         .name("age rule")
    11         .description("Check if person"s age is > 18 and marks the person as adult")
    12         .priority(1)
    13         .when("person.age > 18")
    14         .then("person.setAdult(true);");
    15     //创建规则2
    16     Rule alcoholRule = new MVELRuleFactory(new YamlRuleDefinitionReader()).
    17         createRule(new FileReader(ResourceUtils.getFile("classpath:alcohol-rule.yml")));
    18 
    19     Rules rules = new Rules();
    20     rules.register(ageRule);
    21     rules.register(alcoholRule);
    22 
    23     //创建规则执行引擎,并执行规则
    24     RulesEngine rulesEngine = new DefaultRulesEngine();
    25     System.out.println("Tom: Hi! can I have some Vodka please?");
    26     rulesEngine.fire(rules, facts);
    27     System.out.println(JSON.toJSONString(tom));
    28   }
    29 }
    执行规则

    执行结果如下:

    源码解析

     https://www.cnblogs.com/lay2017/p/12591966.html

    深入了解原理,可以查看github源码:

    https://github.com/j-easy/easy-rules

    https://gitcode.net/mirrors/j-easy/easy-rules

    转:

     https://segmentfault.com/a/1190000022939252

  • 相关阅读:
    自学编程的人,都是怎么找到自己的第一份工作的?
    自学编程的人,都是怎么找到自己的第一份工作的?
    滴滴工程师带你深入理解 TCP 握手分手全过程
    c语言之利用#if #endif来进行注释或者运行不同的主函数
    c语言之字符指针变量和字符数组的异同
    程序员自我学习自我培训指南
    海量存储之十六–一致性和高可用专题、十七
    海量存储之十四、十五
    海量存储系列之十一、十二、十三
    海量存储系列之八、九、十
  • 原文地址:https://www.cnblogs.com/zt007/p/15745365.html
Copyright © 2020-2023  润新知