ルールエンジンEasy Rules使用例(一)

6783 ワード

著作権は著作者の所有になります。いかなる形式の転載も著作者に連絡して授権し、出典を明記してください。
言語:java依存:

    org.jeasy
    easy-rules-core
    3.2.0



    org.jeasy
    easy-rules-support
    3.2.0



    org.jeasy
    easy-rules-mvel
    3.2.0

一、使用シーン       コードを作成する過程で、私達はif...else...文に対してかなり熟知しました。しかし、条件分岐が多い場合、例えば十数個、数十個、百個以上、さらに多くの場合、業務論理コードの中でif...else...文を使用し続けると、このファイルのコードは非常に違和感があります。また、今後、ルールを追加したい場合、このビジネスロジックコードの中でif...else...文を修正します。これは将来のメンテナンスに一定の不便をもたらしました。        このような状況に対しては、規則エンジンを使って解決することが考えられます。ルールエンジンは単なるものではなく、ここで紹介するのはイージールールエンジンの使用である。上のシーンに対して、easuryruleはif...else...のロジックをビジネスロジックコードから抽出し、これらのロジックを他のファイルに保存します。このようにしてから、業務ロジックコードがすっきりしました。また、将来これらの規則を修正したいなら、直接これらの保存規則の書類を探して行けばいいです。easuryruleでは,保存規則は二つの方式があります。一つは使用です。javaファイルともう一つは使用です。ymlファイルはそれぞれ紹介します。
二、使用例       このような場面があるとします。        (1)一つの数字が5で割り切れるなら、「fizz」を出力します。        (2)一つの数字が7で割り切れるなら、「buzz」を出力します。        (3)一つの数字が同時に5と7で割り切れるなら、「fizbuzz」を出力します。        (4)一つの数字が上記の3つの条件を満たさない場合、この数字自体を出力します。
1、ルールエンジンを使わない実現方式:
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("fizzbuzz");
      else if ((i % 5) == 0) System.out.print("fizz");
      else if ((i % 7) == 0) System.out.print("buzz");
      else System.out.print(i);
      System.out.println();
    }
    System.out.println();
  }
}
2.規則を.javaファイルに保存する:    (1)javaルールファイルの内容は以下の通りです。
public class RuleClass {

    @Rule(priority = 1)
    public static class FizzRule {
        @Condition
        public boolean isFizz(@Fact("number") Integer number) {
            return number % 5 == 0;
        }

        @Action
        public void printFizz() {
            System.out.print("fizz");
        }
    }

    @Rule(priority = 2)
    public static class BuzzRule {
        @Condition
        public boolean isBuzz(@Fact("number") Integer number) {
            return number % 7 == 0;
        }

        @Action
        public void printBuzz() {
            System.out.print("buzz");
        }
    }

    public static class FizzBuzzRule extends UnitRuleGroup {

        public FizzBuzzRule(Object... rules) {
            for (Object rule : rules) {
                addRule(rule);
            }
        }

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

    @Rule(priority = 3)
    public static class NonFizzBuzzRule {

        @Condition
        public boolean isNotFizzNorBuzz(@Fact("number") Integer number) {
            // can return true, because this is the latest rule to trigger according to
            // assigned priorities
            // and in which case, the number is not fizz nor buzz
            return number % 5 != 0 || number % 7 != 0;
        }

        @Action
        public void printInput(@Fact("number") Integer number) {
            System.out.print(number);
        }
    }

}
        (2)クライアントコールコードは以下の通りです。
public class RuleClient {
    public static void main(String[] args) {
        // create a rules engine
        RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
        RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);

        // create rules
        Rules rules = new Rules();
        rules.register(new FizzRule());
        rules.register(new BuzzRule());
        rules.register(new RuleClass.FizzBuzzRule(new RuleClass.FizzRule(), new RuleClass.BuzzRule()));
        rules.register(new NonFizzBuzzRule());

        // fire rules
        Facts facts = new Facts();
        for (int i = 1; i <= 100; i++) {
            facts.put("number", i);
            fizzBuzzEngine.fire(rules, facts);
            System.out.println();
        }
    }

}
コードの注釈:注1
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
        この行のコードの役割は次のRulesEngineの作成のための属性です。ここでは一つの属性skype OnFirstAppledRuleだけが設定されています。これは後にRuleClassのルールを実行する時に、一つのルールがトリガされると、現在転送されているFactは他の規則を満たすかどうかを判断しないという意味です。        このような属性はいくつかありますが、次の文章で述べます。
注2        私たちはFactsの使用に注意します。Factsの使い方はMapに似ています。クライアントとルールファイルの間で通信する橋です。クライアントがputメソッドを使用してFactsにデータを追加し、ルールファイルでkeyによって対応するデータを得る。
3.規則ファイルを.ymlファイルに保存します。(1).ymlルールファイルの内容は以下の通りです。
---
name: "fizz rule"
description: "print fizz if the number is multiple of 5"
priority: 1
condition: "number % 5 == 0"
actions:
  - "System.out.println(\"fizz\")"
  
---
name: "buzz rule"
description: "print buzz if the number is multiple of 7"
priority: 2
condition: "number % 7 == 0"
actions:
  - "System.out.println(\"buzz\")"
  
---
name: "fizzbuzz rule"
description: "print fizzbuzz if the number is multiple of 5 and 7"
priority: 0
condition: "number % 5 == 0 && number % 7 == 0"
actions:
  - "System.out.println(\"fizzbuzz\")"
  
---
name: "non fizzbuzz rule"
description: "print the number itself otherwise"
priority: 3
condition: "number % 5 != 0 || number % 7 != 0"
actions:
  - "System.out.println(number)"
        (2)クライアントコールコードは以下の通りです。
public class RuleClient {
   public static void main(String[] args) throws FileNotFoundException {
       // create a rules engine
       RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
       RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);

       // create rules
       Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("fizzbuzz.yml"));

       // fire rules
       Facts facts = new Facts();
       for (int i = 1; i <= 100; i++) {
           facts.put("number", i);
           fizzBuzzEngine.fire(rules, facts);
           System.out.println();
       }
   }

}
実行結果は以下の通りです。
1
2
3
4
fizz
6
buzz
8
9
fizz
11
12
13
buzz
fizz
16
17
18
19
fizz
buzz
22
23
24
fizz
26
27
buzz
29
fizz
31
32
33
34
fizzbuzz
36
37
38
39
fizz
41
buzz
43
44
fizz
46
47
48
buzz
fizz
51
52
53
54
fizz
buzz
57
58
59
fizz
61
62
buzz
64
fizz
66
67
68
69
fizzbuzz
71
72
73
74
fizz
76
buzz
78
79
fizz
81
82
83
buzz
fizz
86
87
88
89
fizz
buzz
92
93
94
fizz
96
97
buzz
99
fizz
関連文書
Easy Rules Wiki
次の編:ルールエンジンEasy Rules使用例(二)