JBoss Rulesサンプルプログラム3

最大値を求めるサンプルプログラム

次は、JBoss Rules の宣言的プログラミングの性質を表すサンプルプログラムを紹介します。

 「宣言的」プログラミングとは、結果を「どのようにして(how)」求めるかを記述するのでなく、結果が「何であるか(what)」を記述することでプログラムを作成していく方法です。 たとえば、最大値を求めるプログラムでは、通常の手続き型(命令型)のプログラム言語で実装する場合、値の集合をすべてチェックするようなループを使ってそれぞれの値を比較し、すべてのチェックが終り、最終的に最大値が得られるというようなプログラムを書くでしょう。ここで、最大値の言葉の定義に立ち返ってみましょう。最大値とは何らかの値の集合の中で一番大きい値です。言い換えると、
  「ある値の集合のすべての値よりも大きいかまたは等しい値」のこと
または、これをさらに言い換えて
  「ある値の集合の中に、その値よりも大きな値が存在しない値」のこと
となります。さて、宣言的プログラミングでは、最大値を求めるプログラムの場合、上記のような最大値の「定義」をそのままプログラムに落とし込みます。

 では、具体的なプログラムを見てみましょう。以下は総務課のメンバー中で最も身長の高い人を選び出すプログラムです。まずは、総務課の個々のメンバーを表すクラスを定義します。

Member.java

package com.sample;

public class Member {
 private String name;
 private String section;
 private int height;

 public Member(String name, String section, int height) {
  super();
  this.name = name;
  this.section = section;
  this.height = height;
 }

 public String getSection() {
  return section;
 }

 public void setSection(String name) {
  this.section = name;
 }

 public int getHeight() {
  return height;
 }

 public void setHeight(int height) {
  this.height = height;
 }
 
 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

}

 

さらに、メインプログラムは、以下のとおりです。

DroolsTest.java

package com.sample;

import java.io.InputStreamReader;
import java.io.Reader;

import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.WorkingMemory;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;

/**
 * This is a sample file to launch a rule package from a rule source file.
 */
public class DroolsTest {

    public static final void main(String[] args) {
        try {
         
         //load up the rulebase
            RuleBase ruleBase = readRule();
            WorkingMemory workingMemory = ruleBase.newWorkingMemory();
                    
            Member memFact1 = new Member(“友里”,”総務”,168);
            workingMemory.assertObject( memFact1 );
            Member memFact2 = new Member(“優”,”総務”,170);
            workingMemory.assertObject( memFact2 );
            Member memFact3 = new Member(“もえ”,”総務”,168);
            workingMemory.assertObject( memFact3 );
            Member memFact4 = new Member(“茉希”,”総務”,168);
            workingMemory.assertObject( memFact4 );
            Member memFact5 = new Member(“紗世”,”総務”,165);
            workingMemory.assertObject( memFact5 );

            workingMemory.fireAllRules();             
           
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    /**
     * Please note that this is the “low level” rule assembly API.
     */
 private static RuleBase readRule() throws Exception {
  //read in the source
  Reader source = new InputStreamReader( DroolsTest.class.getResourceAsStream( “/Sample.drl” ) );
  
  //optionally read in the DSL (if you are using it).
  //Reader dsl = new InputStreamReader( DroolsTest.class.getResourceAsStream( “/mylang.dsl” ) );

  //Use package builder to build up a rule package.
  //An alternative lower level class called “DrlParser” can also be used…
  
  PackageBuilder builder = new PackageBuilder();

  //this wil parse and compile in one step
  //NOTE: There are 2 methods here, the one argument one is for normal DRL.
  builder.addPackageFromDrl( source );

  //Use the following instead of above if you are using a DSL:
  //builder.addPackageFromDrl( source, dsl );
  
  //get the compiled package (which is serializable)
  Package pkg = builder.getPackage();
  
  //add the package to a rulebase (deploy the rule package).
  RuleBase ruleBase = RuleBaseFactory.newRuleBase();
  ruleBase.addPackage( pkg );
  return ruleBase;
 }
   
}

ここまでは、あまり説明の必要はないと思いますが念のため、mainのプログラムでworkingMemory.assertObjectというところで、メンバーのファクトをワーキングメモリーに登録していきます。

最後に肝心なルールのソースです。

sample.drl

package com.sample
 
import com.sample.Member;

rule “maxHeight”
  when
    memMaxHeight: Member( section == “総務”, maxheight : height )
    not Member( section == “総務”, height > maxheight)
  then
    System.out.println(“最も背が高い人の身長は、”+maxheight+”cm”);
    System.out.println(“一番背が高いのは ”
         +memMaxHeight.getName()
         +”で身長”
         +memMaxHeight.getHeight()
         +”cm”);
end

 

when~thenの~の部分を見てください。まずwhen節の2行目は、「maxheightよりも高い身長を持つ総務の人はいない。 」ということを表しています。1行目はそれのみであれば、総務のメンバー全員にマッチしますが、2行目と組み合わせることで、総務のメンバーで自分の身長よりも高い身長を持つメンバーはいないということを表すことになります。

 さて、これを実行すると

最も背が高い人の身長は、170cm
一番背が高いのは 優で身長170cm

という結果が表示されます。ワーキングメモリに登録する総務課のメンバーを追加したり替えてみていろいろとやってみてください。