2.8. DRL のルール条件 (WHEN)
DRL ルールの when
部分 (ルールの左辺 (LHS)とも言う) には、アクションを実行するのに満たされなければならない条件が含まれます。条件は、パッケージ内で使用可能なデータオブジェクトに基づいて、指定された一連の パターン および 制約、オプションの バインディング およびサポートされるルール条件要素 (キーワード) で設定されます。たとえば、銀行のローンの申し込みに年齢制限 (21 歳以上) が必要な場合、"Underage"
ルールの when
条件は Applicant( age < 21 )
となります。
DRL は if
ではなく when
を使用します。これは、if
が一般に手続き型の実行フローの一部であり、条件が特定の時点でチェックされるためです。一方、when
は、条件の評価が特定の評価シーケンスや時点に限定されず、いつでも継続的に行われることを示しています。条件が満たされるたびに、これらのアクションが実施されます。
when
セクションを空にすると、条件は true であると見なされ、デシジョンエンジンで fireAllRules()
呼び出しが最初に実施された場合に、then
セクションのアクションが実行されます。これは、デシジョンエンジンのステートを設定するルールを使用する場合に便利です。
以下のルール例では、空の条件を使用して、ルールが実行するたびにファクトを挿入します。
条件のないルール例
ルールの条件が、定義されたキーワード接続詞 (and
、or
、または not
など) なしで複数のパターンを使用する場合、デフォルトの接続詞は and
になります。
キーワード接続詞なしのルールの例
2.8.1. パターンと制約 リンクのコピーリンクがクリップボードにコピーされました!
DRL ルール条件の パターン は、デシジョンエンジンによって照合されるセグメントです。パターンは、デシジョンエンジンのワーキングメモリーに挿入される各ファクトと一致する可能性があります。パターンには 制約 を含めることもでき、これにより一致するファクトをより詳細に定義できます。
制約のない最も単純なフォームでは、パターンは指定されたタイプのファクトに一致します。以下の例ではタイプが Person
であるため、このパターンはデシジョンエンジンのワーキングメモリーのすべての Person
オブジェクトに一致します。
ファクトタイプが 1 つの場合のパターン例
Person()
Person()
このタイプは、ファクトオブジェクトの実際のクラスである必要はありません。パターンは、複数の異なるクラスのファクトと一致する可能性のあるスーパーユーザーやインターフェイスも参照できます。たとえば、以下のパターンは、デシジョンエンジンのワーキングメモリーにあるすべてのオブジェクトと一致します。
すべてのオブジェクトの場合のパターン例
Object() // Matches all objects in the working memory
Object() // Matches all objects in the working memory
パターンの括弧は制約を囲みます (以下のユーザーの年齢に関する制約など)。
制約のあるパターンの例
Person( age == 50 )
Person( age == 50 )
制約は、true
または false
を返す式です。DRL 内のパターンの制約は、基本的にはプロパティーのアクセスなどの拡張が設定された Java の式ですが、==
および !=
に対する equals()
および !equals()
セマンティクスなど、若干の違いがあります (通常の same
および not same
セマンティクスではありません)。
JavaBean プロパティーはパターンの制約から直接アクセスできます。Bean プロパティーは、引数を使用せずに何かを返す標準の JavaBeans の getter を使用して内部的に公開されます。たとえば、age
プロパティーは、DRL で getter の getAge()
ではなく、age
として記述されます。
JavaBeans プロパティーを使用した DRL 制約構文
Person( age == 50 ) // This is the same as the following getter format: Person( getAge() == 50 )
Person( age == 50 )
// This is the same as the following getter format:
Person( getAge() == 50 )
Red Hat Decision Manager は標準の JDK leavingspector
クラスを使用してこのマッピングを行うため、標準の JavaBeans 仕様に従います。デシジョンエンジンのパフォーマンスの最適化には、getAge()
のように getter を明示的に使用するのではなく、age
のようなプロパティーアクセスの形式を使用します。
デシジョンエンジンは効率化のために呼び出し間で一致した結果をキャッシュするため、プロパティーアクセサーを使用してルールに影響を与える可能性がある方法でオブジェクトの状態を変更しないでください。
たとえば、プロパティーアクセサーを以下のように使用しないでください。
public int getAge() { age++; // Do not do this. return age; }
public int getAge() {
age++; // Do not do this.
return age;
}
public int getAge() { Date now = DateUtil.now(); // Do not do this. return DateUtil.differenceInYears(now, birthday); }
public int getAge() {
Date now = DateUtil.now(); // Do not do this.
return DateUtil.differenceInYears(now, birthday);
}
2 番目の例に従う代わりに、ワーキングメモリーに現在の日付をラップするファクトを挿入し、必要に応じてそのファクトを fireAllRules()
の間で更新します。
ただし、プロパティーの getter が見つからなかった場合、コンパイラーは、以下のようにこのプロパティー名をフォールバックメソッド名として引数なしで使用します。
オブジェクトが見つからない場合のフォールバックメソッド
Person( age == 50 ) // If `Person.getAge()` does not exist, the compiler uses the following syntax: Person( age() == 50 )
Person( age == 50 )
// If `Person.getAge()` does not exist, the compiler uses the following syntax:
Person( age() == 50 )
以下の例のように、パターンでアクセスプロパティーをネストすることもできます。ネストされたプロパティーにはデシジョンエンジンでインデックス化されます。
ネストされたプロパティーアクセスを使用するパターンの例
Person( address.houseNumber == 50 ) // This is the same as the following format: Person( getAddress().getHouseNumber() == 50 )
Person( address.houseNumber == 50 )
// This is the same as the following format:
Person( getAddress().getHouseNumber() == 50 )
ステートフルな KIE セッションでは、ネストされたアクセサーの使用に注意が必要です。デシジョンエンジンのワーキングメモリーではネストされた値は認識されず、これらの値の変更は検出されません。ネストされた値の親参照がワーキングメモリーに挿入されている場合はこれらの値を不変と見なすか、ネストされた値を変更する必要がある場合は、すべての外部ファクトを更新済みとしてマークします。前の例では、houseNumber
プロパティーが変更された場合は、この Address
が指定された Person
は更新済みとしてマークされる必要があります。
パターンの括弧内では boolean
値を制約として返す任意の Java 式を使用できます。Java 式は、プロパティーアクセスなどの他の式の拡張機能と組み合わせることができます。
プロパティーアクセスと Java 式を使用する制約が設定されたパターンの例
Person( age == 50 )
Person( age == 50 )
評価の優先度は、論理式や数式のように括弧を使用して変更できます。
制約の評価順序の例
Person( age > 100 && ( age % 10 == 0 ) )
Person( age > 100 && ( age % 10 == 0 ) )
以下の例のように、制約で Java メソッドを再利用することもできます。
再利用される Java メソッドによる制約の例
Person( Math.round( weight / ( height * height ) ) < 25.0 )
Person( Math.round( weight / ( height * height ) ) < 25.0 )
デシジョンエンジンは効率化を図るために呼び出し間で一致の結果をキャッシュするため、ルールに影響を与える可能性のある方法でオブジェクトの状態を変更するために制約を使用しないでください。ルール条件のファクトで実行されるメソッドは、読み取り専用のメソッドである必要があります。また、ファクトの状態は、ファクトがワーキングメモリーで更新済みとしてマークされているのでない限り、毎回変更されるたびにルールの呼び出し間で変更されません。
たとえば、以下のような方法でパターンの制約を使用しないでください。
Person( incrementAndGetAge() == 10 ) // Do not do this.
Person( incrementAndGetAge() == 10 ) // Do not do this.
Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.
Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.
DRL 内の制約演算子には、標準の Java 演算子の優先順位が適用されます。DRL 演算子は、==
および !=
演算子を除き、標準の Java セマンティクスに従います。
==
演算子は、通常の same
セマンティクスではなく、null 安全な equals()
セマンティクスを使用します。たとえば、Person( firstName == "John" )
というパターンは java.util.Objects.equals(person.getFirstName(), "John")
と同様であり、"John"
は null でないため、このパターンは "John".equals(person.getFirstName())
にも似ています。
!=
演算子は、通常の not same
セマンティクスではなく null 安全な !equals()
セマンティクスを使用します。たとえば、Person( firstName != "John" )
というパターンは、!java.util.Objects.equals(person.getFirstName(), "John")
に似ています。
フィールドと制約の値が異なるタイプの場合、デシジョンエンジンは型強制 (type coercion) を使用して競合を解決し、コンパイルエラーを減らします。たとえば、"ten"
が数値エバリュエーターで文字列として指定される場合は、コンパイルエラーが発生しますが、"10"
は数値 10 に型強制されます。型強制では、フィールドのタイプは常に値のタイプより優先されます。
型強制された値を使用する制約の例
Person( age == "10" ) // "10" is coerced to 10
Person( age == "10" ) // "10" is coerced to 10
制約のグループの場合は、コンマ区切り (,
) を使って、暗黙的な and
の接続的なセマンティクスを使用することができます。
複数の制約があるパターンの例
// Person is at least 50 years old and weighs at least 80 kilograms: Person( age > 50, weight > 80 ) // Person is at least 50 years old, weighs at least 80 kilograms, and is taller than 2 meters: Person( age > 50, weight > 80, height > 2 )
// Person is at least 50 years old and weighs at least 80 kilograms:
Person( age > 50, weight > 80 )
// Person is at least 50 years old, weighs at least 80 kilograms, and is taller than 2 meters:
Person( age > 50, weight > 80, height > 2 )
&&
演算子および ,
演算子のセマンティクスは同じですが、これらは異なる優先順位で解決されます。&&
演算子は ||
演算子より優先され、&&
演算子および ||
演算子はどちらも ,
演算子より優先されます。デシジョンエンジンのパフォーマンスと人による可読性を最適化するために、コンマ演算子は最上位レベルの制約で使用してください。
括弧内など、複合制約式にコンマ演算子を埋め込むことはできません。
複合制約式での不適切なコンマの例
// Do not use the following format: Person( ( age > 50, weight > 80 ) || height > 2 ) // Use the following format instead: Person( ( age > 50 && weight > 80 ) || height > 2 )
// Do not use the following format:
Person( ( age > 50, weight > 80 ) || height > 2 )
// Use the following format instead:
Person( ( age > 50 && weight > 80 ) || height > 2 )