Fact对象的Equality Modes

66 阅读5分钟

Fact对象的Equality Modes详述

在Drools规则引擎中,Fact对象的Equality Modes(相等模式)是一个重要的概念,它决定了规则引擎如何判断工作内存中Fact对象的相等性。Drools中存在两种主要的Equality Modes:Identity模式和Equality模式。下面将详细介绍这两种模式。

一、Identity模式

1.1 定义

Identity模式是Drools的默认相等模式。在这种模式下,Drools引擎使用IdentityHashMap来保存所有插入到工作内存中的Fact对象。对于每次插入一个新的对象,引擎会返回一个新的FactHandle对象;如果重复插入相同的对象,则返回已经存在的FactHandle对象。这里判断对象相等的依据是对象的引用地址,即只有当两个对象是同一个实例时,才认为它们是相等的。

1.2 示例

以下是一个简单的示例代码,展示了Identity模式的特点:

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
​
public class IdentityModeExample {
    public static void main(String[] args) {
        // 创建KieServices实例
        KieServices kieServices = KieServices.Factory.get();
        // 创建KieContainer实例,加载规则
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 创建KieSession实例
        KieSession kieSession = kieContainer.newKieSession();
​
        // 创建两个内容相同但引用不同的Person对象
        Person p1 = new Person("zhangsan", 20, "湖北罗田");
        Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
​
        // 插入对象并获取FactHandle
        FactHandle factHandle1 = kieSession.insert(p1);
        FactHandle factHandle2 = kieSession.insert(p2);
        FactHandle factHandle3 = kieSession.insert(p2);
​
        // 判断FactHandle是否相等
        System.out.println("factHandle1 == factHandle2: " + (factHandle1 == factHandle2)); 
        System.out.println("factHandle2 == factHandle3: " + (factHandle2 == factHandle3)); 
​
        // 触发规则执行
        kieSession.fireAllRules();
        // 释放资源
        kieSession.dispose();
    }
}
​
class Person {
    private String name;
    private int age;
    private String address;
​
    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
​
    // Getter和Setter方法
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getAddress() {
        return address;
    }
​
    public void setAddress(String address) {
        this.address = address;
    }
}

在上述示例中,p1p2虽然内容相同,但它们是不同的对象实例。因此,factHandle1factHandle2不相等;而p2被重复插入,所以factHandle2factHandle3相等。

1.3 特点

  • 严格的相等判断:只根据对象的引用地址来判断相等性,即使两个对象的属性值完全相同,只要引用地址不同,就认为它们是不同的对象。
  • 允许重复属性对象存在:工作内存中可以同时存在多个属性值相同但引用不同的对象。

二、Equality模式

2.1 定义

Equality模式下,Drools引擎使用HashMap来保存所有插入到工作内存中的Fact对象。在插入新对象时,引擎会根据对象的hashCode()equals()方法来判断该对象是否已经存在于工作内存中。只有当插入的对象与现有对象的hashCode()值相同,并且equals()方法返回true时,才认为它们是相等的,此时不会插入新的对象,而是返回已存在对象的FactHandle;否则,会插入新对象并返回新的FactHandle

2.2 示例

以下是一个使用Equality模式的示例代码:

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.conf.EqualityBehaviorOption;
​
import java.util.Objects;
​
public class EqualityModeExample {
    public static void main(String[] args) {
        // 创建KieServices实例
        KieServices kieServices = KieServices.Factory.get();
        // 创建KieBaseConfiguration并设置为Equality模式
        org.kie.api.conf.KieBaseConfiguration kieBaseConfig = kieServices.newKieBaseConfiguration();
        kieBaseConfig.setOption(EqualityBehaviorOption.EQUALITY);
​
        // 创建KieContainer实例,加载规则
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 根据配置创建KieBase
        org.kie.api.KieBase kieBase = kieContainer.newKieBase(kieBaseConfig);
        // 创建KieSession实例
        KieSession kieSession = kieBase.newKieSession();
​
        // 创建两个内容相同的Person对象
        Person p1 = new Person("zhangsan", 20, "湖北罗田");
        Person p2 = new Person("zhangsan", 20, "湖北罗田");
​
        // 重写hashCode和equals方法
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
​
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return age == person.age &&
                    Objects.equals(name, person.name);
        }
​
        // 插入对象并获取FactHandle
        FactHandle factHandle1 = kieSession.insert(p1);
        FactHandle factHandle2 = kieSession.insert(p2);
​
        // 判断FactHandle是否相等
        System.out.println("factHandle1 == factHandle2: " + (factHandle1 == factHandle2)); 
​
        // 触发规则执行
        kieSession.fireAllRules();
        // 释放资源
        kieSession.dispose();
    }
}

在上述示例中,p1p2的属性值相同,并且重写了hashCode()equals()方法。因此,在Equality模式下,factHandle1factHandle2相等,说明工作内存中只插入了一个对象。

2.3 特点

  • 基于属性的相等判断:根据对象的属性值来判断相等性,只要两个对象的属性值相同,就认为它们是相等的。
  • 避免重复对象插入:工作内存中不会存在属性值相同的重复对象,提高了内存使用效率。

三、如何设置Equality模式

3.1 通过kmodule.xml配置

可以在kmodule.xml文件中通过配置kbaseequalsBehavior属性来设置Equality模式。示例如下:

<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="kbase-identity" packages="rules" default="false" equalsBehavior="identity">
        <ksession name="ksession-01" default="false" type="stateful"/>
    </kbase>
    <kbase name="kbase-equality" packages="rules" default="false" equalsBehavior="equality">
        <ksession name="ksession-02" default="false" type="stateful"/>
    </kbase>
</kmodule>

在上述配置中,kbase-identity使用Identity模式,kbase-equality使用Equality模式。

3.2 编程方式设置

也可以在代码中通过KieBaseConfiguration来设置Equality模式。示例如下:

import org.kie.api.KieServices;
import org.kie.api.conf.EqualityBehaviorOption;
import org.kie.api.runtime.KieBase;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
​
public class ProgrammaticEqualityModeExample {
    public static void main(String[] args) {
        // 创建KieServices实例
        KieServices kieServices = KieServices.Factory.get();
        // 创建KieBaseConfiguration并设置为Equality模式
        org.kie.api.conf.KieBaseConfiguration kieBaseConfig = kieServices.newKieBaseConfiguration();
        kieBaseConfig.setOption(EqualityBehaviorOption.EQUALITY);
​
        // 创建KieContainer实例,加载规则
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 根据配置创建KieBase
        KieBase kieBase = kieContainer.newKieBase(kieBaseConfig);
        // 创建KieSession实例
        KieSession kieSession = kieBase.newKieSession();
​
        // 后续操作...
    }
}

四、总结

Identity模式和Equality模式各有优缺点,在实际应用中需要根据具体需求来选择合适的模式。

  • Identity模式:适用于需要严格区分对象引用的场景,例如在某些情况下需要确保工作内存中存在多个属性相同但引用不同的对象。
  • Equality模式:适用于只关注对象属性值,希望避免工作内存中出现重复对象的场景,可以提高内存使用效率。

通过合理设置Fact对象的Equality Modes,可以更好地控制Drools规则引擎的行为,提高规则执行的效率和准确性。