Motor de reglas Easy Rules (2-Detalles)

1. Prefacio

En el motor de reglas Easy Rules (1-Conceptos básicos), presentamos brevemente Easy Ruleslos ejemplos de uso del motor de reglas. En esta sección, explicaremos en detalle los ejemplos de configuración de parámetros relevantes y las reglas de combinación del motor de reglas.


2. Ejemplo de configuración de parámetros del motor de reglas

Easy RulesEl motor de reglas admite la siguiente configuración de parámetros:

nombre del parámetro Tipo de parámetro requerido valor por defecto
reglaPrioridadUmbral En t No Entero.MAX_VALUE
skipOnFirstAppliedRule booleano No FALSO
skipOnFirstFailedRule booleano No FALSO
skipOnFirstNonTriggeredRule booleano No FALSO
  • skipOnFirstAppliedRule: si se debe omitir la siguiente regla cuando se activa la regla y el comportamiento se ejecuta correctamente.
  • skipOnFirstFailedRule: Al juzgar si se activa una regla, se lanza una excepción o si se omite la siguiente regla si se lanza una excepción después de que el disparador es exitoso pero se ejecuta el comportamiento.
  • skipOnFirstNonTriggeredRule : si se debe omitir la siguiente regla cuando la regla no se activa.
  • rulePriorityThreshold : si la prioridad de la regla excede el umbral predeterminado, se omite la siguiente regla.

1. Ejemplo de skipOnFirstAppliedRules

(1) Regla Fizz

import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Priority;
import org.jeasy.rules.annotation.Rule;

/**
 * 被5整除的规则
 * @author Nick Liu
 * @date 2023/8/4
 */
@Rule
public class FizzRule {
    
    

	@Condition
	public boolean isFizz(@Fact("number") Integer number) {
    
    
		return number % 5 == 0;
	}

	@Action
	public void printFizz(@Fact("number") Integer number) throws Exception {
    
    
		System.out.println("能被5整除的数为: " + number);
	}

	@Priority
	public int getPriority() {
    
    
		return 1;
	}

}

(2) Regla de Buzz

import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Priority;
import org.jeasy.rules.annotation.Rule;

/**
 * 被7整除的规则
 * @author Nick Liu
 * @date 2023/8/4
 */
@Rule
public class BuzzRule {
    
    

	@Condition
	public boolean isBuzz(@Fact("number") Integer number) {
    
    
		return number % 7 == 0;
	}

	@Action
	public void printBuzz(@Fact("number") Integer number) throws Exception {
    
    
		System.out.println("能被7整除的数为: " + number);
	}

	@Priority
	public int getPriority() {
    
    
		return 2;
	}
}

(3) Regla FizzBuzz

import org.jeasy.rules.support.composite.UnitRuleGroup;

import java.util.Arrays;

/**
 * 既能被5整除也能被7整除的规则
 * @author Nick Liu
 * @date 2023/8/4
 */
public class FizzBuzzRule extends UnitRuleGroup {
    
    

	public FizzBuzzRule(Object... rules) {
    
    
		Arrays.stream(rules).forEach(super::addRule);
	}

	@Override
	public int getPriority() {
    
    
		return 0;
	}
}

(4) Regla sin FizzBuzz

import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Priority;
import org.jeasy.rules.annotation.Rule;

/**
 * 既不能被5整除也不能被7整除的规则
 * @author Nick Liu
 * @date 2023/8/4
 */
@Rule
public class NonFizzBuzzRule {
    
    

	@Condition
	public boolean isNotFizzOrBuzz(@Fact("number") Integer number) {
    
    
		return number % 5 != 0 || number % 7 != 0;
	}

	@Action
	public void printInput(@Fact("number") Integer number) throws Exception {
    
    
		System.out.println("既不能被5整除也不能被7整除的数字: " + number);
	}

	@Priority
	public int getPriority() {
    
    
		return 3;
	}

}

(5) Lanzador de reglas FizzBuzz

import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.api.RulesEngineParameters;
import org.jeasy.rules.core.DefaultRulesEngine;

/**
 * @author Nick Liu
 * @date 2023/8/4
 */
public class FizzBuzzRulesLauncher {
    
    

	public static void main(String[] args) {
    
    
		// 如果第一条规则满足条件且行为执行成功后则跳过执行后面的规则
		RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
		RulesEngine rulesEngine = new DefaultRulesEngine(parameters);

		// 规则注册
		Rules rules = new Rules();
		rules.register(new FizzRule());
		rules.register(new BuzzRule());
		rules.register(new FizzBuzzRule(new FizzRule(), new BuzzRule()));
		rules.register(new NonFizzBuzzRule());

		// 触发规则
		Facts facts = new Facts();
		for (int count = 0; count < 100; count++) {
    
    
			facts.put("number", count);
			rulesEngine.fire(rules, facts);
		}
	}
}

Arriba configuramos skipOnFirstAppliedRuleel atributo del motor de reglas predeterminado en true . La regla con mayor prioridad es FizzBuzzRuleque es una regla combinada, es decir, cuando se cumplen las condiciones de la regla combinada y el comportamiento de la regla se ejecuta con éxito, el Se omitirán las siguientes reglas de baja prioridad. Se omitirán todas las reglas de nivel.

En pocas palabras, el orden de ejecución de las reglas anteriores es FizzBuzzRuleFizzRuleBuzzRuleNonFizzBuzzRule. La semántica es juzgar primero si el número es divisible por 5 y 7 al mismo tiempo, luego juzgar si es divisible por 5 y luego juzgar si es divisible por 7 y finalmente juzga si no es divisible por 5. O divisible por 7.

Los resultados de ejecutar el programa son los siguientes:

能被5整除的数为: 0
能被7整除的数为: 0
既不能被5整除也不能被7整除的数字: 1
既不能被5整除也不能被7整除的数字: 2
既不能被5整除也不能被7整除的数字: 3
既不能被5整除也不能被7整除的数字: 4
能被5整除的数为: 5
既不能被5整除也不能被7整除的数字: 6
能被7整除的数为: 7
既不能被5整除也不能被7整除的数字: 8
既不能被5整除也不能被7整除的数字: 9
能被5整除的数为: 10
既不能被5整除也不能被7整除的数字: 11
既不能被5整除也不能被7整除的数字: 12
既不能被5整除也不能被7整除的数字: 13
能被7整除的数为: 14
能被5整除的数为: 15
既不能被5整除也不能被7整除的数字: 16
既不能被5整除也不能被7整除的数字: 17
既不能被5整除也不能被7整除的数字: 18
既不能被5整除也不能被7整除的数字: 19
能被5整除的数为: 20
能被7整除的数为: 21
既不能被5整除也不能被7整除的数字: 22
既不能被5整除也不能被7整除的数字: 23
既不能被5整除也不能被7整除的数字: 24
能被5整除的数为: 25
既不能被5整除也不能被7整除的数字: 26
既不能被5整除也不能被7整除的数字: 27
能被7整除的数为: 28
既不能被5整除也不能被7整除的数字: 29
能被5整除的数为: 30
既不能被5整除也不能被7整除的数字: 31
既不能被5整除也不能被7整除的数字: 32
既不能被5整除也不能被7整除的数字: 33
既不能被5整除也不能被7整除的数字: 34
能被5整除的数为: 35
能被7整除的数为: 35
既不能被5整除也不能被7整除的数字: 36
既不能被5整除也不能被7整除的数字: 37
既不能被5整除也不能被7整除的数字: 38
既不能被5整除也不能被7整除的数字: 39
能被5整除的数为: 40
既不能被5整除也不能被7整除的数字: 41
能被7整除的数为: 42
既不能被5整除也不能被7整除的数字: 43
既不能被5整除也不能被7整除的数字: 44
能被5整除的数为: 45
既不能被5整除也不能被7整除的数字: 46
既不能被5整除也不能被7整除的数字: 47
既不能被5整除也不能被7整除的数字: 48
能被7整除的数为: 49
能被5整除的数为: 50
既不能被5整除也不能被7整除的数字: 51
既不能被5整除也不能被7整除的数字: 52
既不能被5整除也不能被7整除的数字: 53
既不能被5整除也不能被7整除的数字: 54
能被5整除的数为: 55
能被7整除的数为: 56
既不能被5整除也不能被7整除的数字: 57
既不能被5整除也不能被7整除的数字: 58
既不能被5整除也不能被7整除的数字: 59
能被5整除的数为: 60
既不能被5整除也不能被7整除的数字: 61
既不能被5整除也不能被7整除的数字: 62
能被7整除的数为: 63
既不能被5整除也不能被7整除的数字: 64
能被5整除的数为: 65
既不能被5整除也不能被7整除的数字: 66
既不能被5整除也不能被7整除的数字: 67
既不能被5整除也不能被7整除的数字: 68
既不能被5整除也不能被7整除的数字: 69
能被5整除的数为: 70
能被7整除的数为: 70
既不能被5整除也不能被7整除的数字: 71
既不能被5整除也不能被7整除的数字: 72
既不能被5整除也不能被7整除的数字: 73
既不能被5整除也不能被7整除的数字: 74
能被5整除的数为: 75
既不能被5整除也不能被7整除的数字: 76
能被7整除的数为: 77
既不能被5整除也不能被7整除的数字: 78
既不能被5整除也不能被7整除的数字: 79
能被5整除的数为: 80
既不能被5整除也不能被7整除的数字: 81
既不能被5整除也不能被7整除的数字: 82
既不能被5整除也不能被7整除的数字: 83
能被7整除的数为: 84
能被5整除的数为: 85
既不能被5整除也不能被7整除的数字: 86
既不能被5整除也不能被7整除的数字: 87
既不能被5整除也不能被7整除的数字: 88
既不能被5整除也不能被7整除的数字: 89
能被5整除的数为: 90
能被7整除的数为: 91
既不能被5整除也不能被7整除的数字: 92
既不能被5整除也不能被7整除的数字: 93
既不能被5整除也不能被7整除的数字: 94
能被5整除的数为: 95
既不能被5整除也不能被7整除的数字: 96
既不能被5整除也不能被7整除的数字: 97
能被7整除的数为: 98
既不能被5整除也不能被7整除的数字: 99

2. Ejemplo de skipOnFirstNonTriggeredRule

public class FizzBuzzRulesLauncher {
    
    

	public static void main(String[] args) {
    
    
		RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstNonTriggeredRule(true);
		RulesEngine rulesEngine = new DefaultRulesEngine(parameters);

		// 规则注册
		Rules rules = new Rules();
		rules.register(new FizzRule());
		rules.register(new BuzzRule());
		rules.register(new FizzBuzzRule(new FizzRule(), new BuzzRule()));
		rules.register(new NonFizzBuzzRule());

		// 触发规则
		Facts facts = new Facts();
		for (int count = 0; count < 100; count++) {
    
    
			facts.put("number", count);
			rulesEngine.fire(rules, facts);
		}
	}
}

Aquí ajustamos los parámetros del motor de reglas a skipOnFirstNonTriggeredRule, lo que significa que cuando no se activa la regla de mayor prioridad, se omitirán las siguientes reglas. Los resultados de la ejecución son los siguientes:

能被5整除的数为: 0
能被7整除的数为: 0
能被5整除的数为: 0
能被7整除的数为: 0
能被5整除的数为: 35
能被7整除的数为: 35
能被5整除的数为: 35
能被7整除的数为: 35
能被5整除的数为: 70
能被7整除的数为: 70
能被5整除的数为: 70
能被7整除的数为: 70

3. Ejemplo de skipOnFirstFailedRule

**
 *5整除的规则
 * @author Nick Liu
 * @date 2023/8/4
 */
@Rule
public class FizzRule {
    
    

	@Condition
	public boolean isFizz(@Fact("number") Integer number) {
    
    
		return number % 5 == 0;
	}

	@Action
	public void printFizz(@Fact("number") Integer number) throws Exception {
    
    
		System.out.println("能被5整除的数为: " + number);
		throw new RuntimeException("该数字能被5整除");
	}

	@Priority
	public int getPriority() {
    
    
		return 1;
	}

}

Aquí modificamos FizzRuleel comportamiento de ejecución después de que se activa la regla. Cuando el número es divisible por 5, se lanza una excepción después del comportamiento de ejecución.

public class FizzBuzzRulesLauncher {
    
    

	public static void main(String[] args) {
    
    
		RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstFailedRule(true);
		RulesEngine rulesEngine = new DefaultRulesEngine(parameters);

		// 规则注册
		Rules rules = new Rules();
		rules.register(new FizzRule());
		rules.register(new BuzzRule());
		rules.register(new FizzBuzzRule(new FizzRule(), new BuzzRule()));
		rules.register(new NonFizzBuzzRule());

		// 触发规则
		Facts facts = new Facts();
		for (int count = 0; count < 100; count++) {
    
    
			facts.put("number", count);
			rulesEngine.fire(rules, facts);
		}
	}
}

Aquí configuramos los parámetros del motor de reglas skipOnFirstFailedRule, es decir, cuando ocurre una excepción al juzgar si se activa una regla o si ocurre una excepción al ejecutar un comportamiento, se omitirá la siguiente regla. Los resultados de ejecución del programa son los siguientes:

能被5整除的数为: 0
既不能被5整除也不能被7整除的数字: 1
既不能被5整除也不能被7整除的数字: 2
既不能被5整除也不能被7整除的数字: 3
既不能被5整除也不能被7整除的数字: 4
能被5整除的数为: 5
既不能被5整除也不能被7整除的数字: 6
能被7整除的数为: 7
既不能被5整除也不能被7整除的数字: 7
既不能被5整除也不能被7整除的数字: 8
既不能被5整除也不能被7整除的数字: 9
能被5整除的数为: 10
既不能被5整除也不能被7整除的数字: 11
既不能被5整除也不能被7整除的数字: 12
既不能被5整除也不能被7整除的数字: 13
能被7整除的数为: 14
既不能被5整除也不能被7整除的数字: 14
能被5整除的数为: 15
既不能被5整除也不能被7整除的数字: 16
既不能被5整除也不能被7整除的数字: 17
既不能被5整除也不能被7整除的数字: 18
既不能被5整除也不能被7整除的数字: 19
能被5整除的数为: 20
能被7整除的数为: 21
既不能被5整除也不能被7整除的数字: 21
既不能被5整除也不能被7整除的数字: 22
既不能被5整除也不能被7整除的数字: 23
既不能被5整除也不能被7整除的数字: 24
能被5整除的数为: 25
既不能被5整除也不能被7整除的数字: 26
既不能被5整除也不能被7整除的数字: 27
能被7整除的数为: 28
既不能被5整除也不能被7整除的数字: 28
既不能被5整除也不能被7整除的数字: 29
能被5整除的数为: 30
既不能被5整除也不能被7整除的数字: 31
既不能被5整除也不能被7整除的数字: 32
既不能被5整除也不能被7整除的数字: 33
既不能被5整除也不能被7整除的数字: 34
能被5整除的数为: 35
既不能被5整除也不能被7整除的数字: 36
既不能被5整除也不能被7整除的数字: 37
既不能被5整除也不能被7整除的数字: 38
既不能被5整除也不能被7整除的数字: 39
能被5整除的数为: 40
既不能被5整除也不能被7整除的数字: 41
能被7整除的数为: 42
既不能被5整除也不能被7整除的数字: 42
既不能被5整除也不能被7整除的数字: 43
既不能被5整除也不能被7整除的数字: 44
能被5整除的数为: 45
既不能被5整除也不能被7整除的数字: 46
既不能被5整除也不能被7整除的数字: 47
既不能被5整除也不能被7整除的数字: 48
能被7整除的数为: 49
既不能被5整除也不能被7整除的数字: 49
能被5整除的数为: 50
既不能被5整除也不能被7整除的数字: 51
既不能被5整除也不能被7整除的数字: 52
既不能被5整除也不能被7整除的数字: 53
既不能被5整除也不能被7整除的数字: 54
能被5整除的数为: 55
能被7整除的数为: 56
既不能被5整除也不能被7整除的数字: 56
既不能被5整除也不能被7整除的数字: 57
既不能被5整除也不能被7整除的数字: 58
既不能被5整除也不能被7整除的数字: 59
能被5整除的数为: 60
既不能被5整除也不能被7整除的数字: 61
既不能被5整除也不能被7整除的数字: 62
能被7整除的数为: 63
既不能被5整除也不能被7整除的数字: 63
既不能被5整除也不能被7整除的数字: 64
能被5整除的数为: 65
既不能被5整除也不能被7整除的数字: 66
既不能被5整除也不能被7整除的数字: 67
既不能被5整除也不能被7整除的数字: 68
既不能被5整除也不能被7整除的数字: 69
能被5整除的数为: 70
既不能被5整除也不能被7整除的数字: 71
既不能被5整除也不能被7整除的数字: 72
既不能被5整除也不能被7整除的数字: 73
既不能被5整除也不能被7整除的数字: 74
能被5整除的数为: 75
既不能被5整除也不能被7整除的数字: 76
能被7整除的数为: 77
既不能被5整除也不能被7整除的数字: 77
既不能被5整除也不能被7整除的数字: 78
既不能被5整除也不能被7整除的数字: 79
能被5整除的数为: 80
既不能被5整除也不能被7整除的数字: 81
既不能被5整除也不能被7整除的数字: 82
既不能被5整除也不能被7整除的数字: 83
能被7整除的数为: 84
既不能被5整除也不能被7整除的数字: 84
能被5整除的数为: 85
既不能被5整除也不能被7整除的数字: 86
既不能被5整除也不能被7整除的数字: 87
既不能被5整除也不能被7整除的数字: 88
既不能被5整除也不能被7整除的数字: 89
能被5整除的数为: 90
能被7整除的数为: 91
既不能被5整除也不能被7整除的数字: 91
既不能被5整除也不能被7整除的数字: 92
既不能被5整除也不能被7整除的数字: 93
既不能被5整除也不能被7整除的数字: 94
能被5整除的数为: 95
既不能被5整除也不能被7整除的数字: 96
既不能被5整除也不能被7整除的数字: 97
能被7整除的数为: 98
既不能被5整除也不能被7整除的数字: 98
既不能被5整除也不能被7整除的数字: 99

Como puedes ver, los números que son divisibles por 5 y 7, como 35 y 70 , solo se imprimen una vez.


3. Reglas de combinación

Easy RulesNos permite crear reglas de combinación complejas . Las llamadas reglas de combinación se componen de múltiples reglas únicas, que en realidad son una implementación del patrón de diseño de combinación.

La combinación de reglas es un concepto abstracto porque la combinación de reglas se puede abordar de diferentes maneras. Easy RulesSe proporcionan implementaciones de tres reglas de combinación. Estas implementaciones se pueden easy-rules-supportencontrar en el módulo. Primero, se introducen las tres reglas de combinación:

  • UnitRuleGroup: grupo de reglas de unidad, se aplicarán todas las reglas que contiene.
  • ActivationRuleGroup: al activar un grupo de reglas, solo se activará la primera regla aplicable. Todas las reglas del grupo de reglas están ordenadas por prioridad de forma predeterminada.
  • ConditionalRuleGroup: regla condicional, si se puede activar la regla de mayor prioridad, se activarán las reglas de otros grupos de reglas.

1. Reglas de combinación de UnitRuleGroup

El código de esta regla combinada para determinar si la regla se activa es el siguiente: puede ver que si se activan todas las reglas, se ejecutará el comportamiento correspondiente.

@Override
public boolean evaluate(Facts facts) {
    
    
    if (!rules.isEmpty()) {
    
    
        for (Rule rule : rules) {
    
    
            if (!rule.evaluate(facts)) {
    
    
                return false;
            }
        }
        return true;
    }
    return false;
}

@Override
public void execute(Facts facts) throws Exception {
    
    
    for (Rule rule : rules) {
    
    
        rule.execute(facts);
    }
}

2. Reglas de combinación de ActivationRuleGroup

Del código fuente de esta regla combinada, podemos ver que solo la primera regla en el grupo de reglas que se puede activar ejecutará el comportamiento de regla correspondiente.

@Override
public boolean evaluate(Facts facts) {
    
    
   for (Rule rule : rules) {
    
    
       if (rule.evaluate(facts)) {
    
    
           selectedRule = rule;
           return true;
       }
   }
   return false;
}

@Override
public void execute(Facts facts) throws Exception {
    
    
   if (selectedRule != null) {
    
    
       selectedRule.execute(facts);
   }
}

3. Reglas de combinación de ConditionalRuleGroup

El código fuente de esta regla combinada es el siguiente: puede ver que solo se puede activar la regla de mayor prioridad y luego se seguirán aplicando las reglas de otras reglas.

 @Override
 public boolean evaluate(Facts facts) {
    
    
     successfulEvaluations = new HashSet<>();
     conditionalRule = getRuleWithHighestPriority();
     if (conditionalRule.evaluate(facts)) {
    
    
         for (Rule rule : rules) {
    
    
             if (rule != conditionalRule && rule.evaluate(facts)) {
    
    
                 successfulEvaluations.add(rule);
             }
         }
         return true;
     }
     return false;
 }

 /**
  * When a conditional rule group is executed, all rules that evaluated to true
  * are performed in their natural order, but with the conditional rule 
  * (the one with the highest priority) first.
  *
  * @param facts The facts.
  *
  * @throws Exception thrown if an exception occurs during actions performing
  */
 @Override
 public void execute(Facts facts) throws Exception {
    
    
     conditionalRule.execute(facts);
     for (Rule rule : sort(successfulEvaluations)) {
    
    
         rule.execute(facts);
     }
 }

 private Rule getRuleWithHighestPriority() {
    
    
     List<Rule> copy = sort(rules);
     // make sure we only have one rule with the highest priority
     Rule highest = copy.get(0);
     if (copy.size() > 1 && copy.get(1).getPriority() == highest.getPriority()) {
    
    
        throw new IllegalArgumentException("Only one rule can have highest priority");
     }
     return highest;
 }

 private List<Rule> sort(Set<Rule> rules) {
    
    
     return new ArrayList<>(new TreeSet<>(rules));
 }

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/lingbomanbu_lyl/article/details/132222367
Recomendado
Clasificación