Drools中如何将已有对象赋值给新建对象并修改新对象字段值
规则报错与不生效的核心原因
你写的规则存在3个本质问题,既会触发运行异常,也无法实现「原对象不被改动」的要求:
- Drools规则的
when块(LHS)是事实匹配逻辑,不是变量赋值逻辑,你写的$newObject:$customerObject;属于非法的重复变量绑定写法,会直接触发规则解析/运行错误。 when块中写$newObject:Customer()是要求工作内存(Working Memory)中必须提前存在另一个独立的Customer事实才能触发规则,既无法自动生成和原对象属性一致的副本,没提前插入对应事实时规则根本不会命中。- 你在
then块直接修改$customerObject的字段,本质是直接修改插入工作内存的原对象实例;就算你写了$newObject = $customerObject这种Java引用赋值,两个变量也会指向同一块堆内存,修改新变量字段时原对象还是会被改动,完全达不到隔离效果。
正确实现方案
要实现「基于原对象生成独立副本、修改副本不影响原对象、副本传递到后续流程」的需求,遵循两个原则即可:
- 所有对象创建、复制操作全部放在
then块(RHS)实现,when块只做原事实的条件匹配 - 必须生成独立的Customer新实例做属性复制,禁止直接把原对象引用赋值给新变量
可直接运行的规则示例如下:
rule "example" when // 仅匹配符合条件的原Customer对象,不需要在when块声明新对象 $customerObject : Customer(nameOfBank=="AXIS", salary>=70000) then // 1. 创建独立的Customer新实例 Customer $newObject = new Customer(); // 复制原对象所有需要保留的属性到新实例 $newObject.setNameOfBank($customerObject.getNameOfBank()); $newObject.setSalary($customerObject.getSalary()); // 其余需要保留的属性按上述方式逐行复制即可,也可以用BeanUtils、MapStruct这类Bean拷贝工具减少重复代码 // 如果Customer类实现了Cloneable接口,也可以直接用 Customer $newObject = (Customer) $customerObject.clone(); 快速生成副本,注意默认clone是浅拷贝,存在嵌套引用类型属性时要自行实现深拷贝 // 2. 仅修改新对象的字段,绝对不要操作$customerObject的字段,避免改动原对象 $newObject.setIsAligibleforLoan("Yes"); $newObject.setRateOfInterest(12); $newObject.setDocumentNeeded("Yes"); // 3. 传递新对象到后续流程 DocumentCheck($newObject); // 如果后续其他规则需要用到这个新生成的对象,执行insert($newObject)将其加入工作内存即可 halt(); end
注意:如果Customer类存在自定义引用类型的成员变量(比如联系方式、地址类属性),一定要做深拷贝,避免新对象和原对象共用嵌套属性的引用,导致修改新对象嵌套字段时意外改动原对象数据。
内容的提问来源于stack exchange,提问作者BeYou
相关产品推荐
相关产品推荐

