规则引擎的目的是以松散灵活的方式来替代硬编码式的if else判断,来达到解耦的目的
easy-rules
easy-rules是个轻量级的规则引擎库,提供了注解等多种配置方式
使用实例
(1)如果一个数字可以被5整除,则输出是5的倍数;
(2)如果一个数字可以被8整除,则输出是8的倍数”;
(3)如果一个数字可以同时被5和8整除,则输出是5的倍数 是8的倍数;
(4)如果一个数字不满足以上三个条件,则输出这个数字本身
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-core</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-support</artifactId> <version>3.2.0</version> </dependency>
<dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-mvel</artifactId> <version>3.2.0</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
public class RuleClass {
public static class FiveAndEightMultipleRule extends UnitRuleGroup {
public FiveAndEightMultipleRule(Object... rules) { for(Object rule : rules){ addRule(rule); } }
@Override public int getPriority() { return 0; } }
@Rule(priority = 1) public static class FiveMultipleRule{
@Condition public boolean isFiveMultiple(@Fact("number") Integer number){ return number % 5 == 0; }
@Action public void print(@Fact("number") Integer number){ System.out.println(number + " is 5 Multiple"); } }
@Rule(priority = 2) public static class EightMultipleRule{
@Condition public boolean isEightMultiple(@Fact("number") Integer number){ return number % 8 == 0; }
@Action public void print(@Fact("number") Integer number){ System.out.println(number + " is 8 Multiple"); } }
@Rule(priority = 3) public static class NoneFiveAndEightMultipleRule{
@Condition public boolean isNoneFiveAndEightMultiple(@Fact("number") Integer number){ return number % 5 != 0 && number % 8 != 0; }
@Action public void print(@Fact("number") Integer number){ System.out.println(number); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class RuleClient {
public static void main(String[] args) {
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true); RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
Rules rules = new Rules(); rules.register(new RuleClass.FiveAndEightMultipleRule(new RuleClass.FiveMultipleRule(), new RuleClass.EightMultipleRule())); rules.register(new RuleClass.FiveMultipleRule()); rules.register(new RuleClass.EightMultipleRule()); rules.register(new RuleClass.NoneFiveAndEightMultipleRule());
Facts facts = new Facts(); for(int i=1; i<=100; i++){ facts.put("number", i); rulesEngine.fire(rules, facts); }
} }
|
@Rule定义规则,priority设置规则的优先级,@Condition规则触发的条件,@Action标注的方法触发的动作,Facts的用法很像Map,可将其作为参数传入@Condition和@Action标注的方法
原理
可以观察下注册规则时rules的register方法
1 2 3 4
| rules.register(new RuleClass.FiveAndEightMultipleRule(new RuleClass.FiveMultipleRule(), new RuleClass.EightMultipleRule())); rules.register(new RuleClass.FiveMultipleRule()); rules.register(new RuleClass.EightMultipleRule()); rules.register(new RuleClass.NoneFiveAndEightMultipleRule());
|
其源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public void register(Object rule) { Objects.requireNonNull(rule); this.rules.add(RuleProxy.asRule(rule)); }
public static Rule asRule(Object rule) { Rule result; if (rule instanceof Rule) { result = (Rule)rule; } else { ruleDefinitionValidator.validateRuleDefinition(rule); result = (Rule)Proxy.newProxyInstance(Rule.class.getClassLoader(), new Class[]{Rule.class, Comparable.class}, new RuleProxy(rule)); }
return result; }
|
可以看到,如果有实现Rule接口,则直接返回,没有的话(即基于注解的形式),则利用JDK的动态代理进行包装
easy-rules还提供了通过配置文件来定义规则,这里不再描述