Easy Rules规则引擎(续)- 条件评估

430 阅读2分钟

前言

本来这个主题已经写完了,不过回头看了一下,感觉评估的功能也很有意思,列个单章介绍一下吧。

评估接口

Condition 是一个函数声明接口,就只有一个方法 boolean evaluate(facts),用于评估规则是否满足既定事实。
这两个类似枚举的接口属性比较有意思,在RuleBuilder源码里就有用到。

  • FALSE:总是返回false的条件实体。
  • TRUE:总是返回true的条件实体。
@FunctionalInterface
public interface Condition {
    /**
     * 根据已知事实评估规则
     */
    boolean evaluate(Facts facts);
    /**
     * A NoOp {@link Condition} that always returns false.
     */
    Condition FALSE = facts -> false;
    /**
     * A NoOp {@link Condition} that always returns true.
     */
    Condition TRUE = facts -> true;
}

常规评估方式

这里用RuleBuilder的例子来说明。

Rule codeRule = new RuleBuilder()
                .name("builder-rule")
                .description("这是代码规则")
                .priority(5)
                .when(facts -> (int) facts.get("age") > 18)
                .then(facts -> System.out.println("builder rule 被触发1,年龄大于18."))
                .build();

RuleBuilder源码

在方法when里限定了规则的触发条件,其实是创建了一个Condition的实体,并在DefaultRule.evaluate()方法里进行规则评估。
condition默认值为Condition.FALSE,如果不设定条件,则规则永远不会被执行。

public class RuleBuilder {
    private Condition condition = Condition.FALSE;
    /**
     * 设置规则触发条件
     */
    public RuleBuilder when(Condition condition) {
        this.condition = condition;
        return this;
    }
    ... 忽略其他代码
    public Rule build() {
        // 创建默认规则实体
        return new DefaultRule(name, description, priority, condition, actions);
    }
}

DefaultRule评估

此类构建比较简单,可以看出评估的方式是根据创建规则时写入的条件进行判定。

class DefaultRule extends BasicRule {
    ...忽略无关代码
    @Override
    public boolean evaluate(Facts facts) {
        return condition.evaluate(facts);
    }
}

注解评估

这里带一嘴,注解规则是通过RuleProxy进行代理的,评估方式是解析注解【@Condition】的方法,用java的反射机制来处理【conditionMethod】。
image.png
可以参照RuleProxy类的这个方法【invoke】。

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        String methodName = method.getName();
        switch (methodName) {
            case "getName":
                return getRuleName();
            ...
            case "evaluate":
                return evaluateMethod(args);
            case "execute":
                return executeMethod(args);
            ...
            default:
                return null;
        }
    }

表达式评估

可以这么说,easy-rules组件里,评估分类两种,表达式和其他,因为Condition接口的实现类只有【MVELCondition】

注意:evaluate方法里有个注释,不接受已编译的表达式...

public class MVELCondition implements Condition {
    private final Serializable compiledExpression;
    /**
     * 用表达式语法创建一个条件实体
     */
    public MVELCondition(String expression) {
        compiledExpression = MVEL.compileExpression(expression);
    }
    @Override
    public boolean evaluate(Facts facts) {
        // MVEL.evalToBoolean does not accept compiled expressions..
        return (boolean) MVEL.executeExpression(compiledExpression, facts.asMap());
    }
}

用上一章的例子来说明

        Facts factSet = new Facts();
        factSet.add(new Fact<>("age", 28));
        // 表达式规则
        Rule elRule = new MVELRule()
                .name("el-rule")
                .priority(9)
                .description("这是表达式规则")
                .when("age > 15")
                .then("System.out.println("el rule 被触发,年龄大于15.");");
        rules.register(elRule);

最终是做一个数值大小的比较,在MathProcessor中做最终判定。
image.png