【问题标题】:Performance and maintainability of making Java calls in "then" of Drools在 Drools 的“then”中进行 Java 调用的性能和可维护性
【发布时间】:2015-07-20 13:08:38
【问题描述】:

我正在开发一个drools 项目,其中每个.drl 文件都是从velocity template 动态创建的。我已经在.drl 文件本身的then 中编写了条件检查成功后要执行的所有计算和操作。

假设一个简单的条件

rule "Rule %"
no-loop
salience 10

when
    $var: Map( this["Key"] == "SomeValue" )
then
    $var.put("Discount%", Do-SOME-%-CALCULATION AND PUT IT HERE)
end

rule "Rule Amt"
no-loop
salience 9

when
    $var: Map( this["Key"] == "SomeValue" )
then
    $var.put("DiscountAmt", Do-SOME-Amt-CALCULATION AND PUT IT HERE)
end

rule "Rule % Amt"
no-loop
salience 8

when
    $var: Map( this["Key"] == "SomeValue" )
then
    $var.put("Discount%", Do-SOME-%-CALCULATION AND PUT IT HERE)
    $var.put("DiscountAmt", Do-SOME-Amt-CALCULATION AND PUT IT HERE)
end

为了形成这些类型的 DRL 文件,我形成了 velocity template like this

#set($d = "$")

rule "$rule.name $rule.type"
no-loop
salience $rule.priority

when
    ${d}var: Map( this["$rule.keyName"] == "$rule.keyValue" )
then
    #if( $rule.type == "%" )
        ${d}var.put("Discount%", CODE-FOR-%-CALCULATION);
    #elseif( $rule.type == "Amt" )
        ${d}var.put("DiscountAmt", CODE-FOR-AMT-CALCULATION);
    #elseif( $rule.type == "% Amt" )
        ${d}var.put("Discount%", CODE-FOR-%-CALCULATION);
        ${d}var.put("DiscountAmt", CODE-FOR-AMT-CALCULATION);
    #end

我知道最后一个#elseif( $rule.type == "% Amt" ) 可以通过利用前两个ifelseif 来消除,方法是将|| $rule.type == "% Amt" 放在这两个条件中。但这只是一个例子。

假设我没有任何选择将这 3 个条件简化为 2 个条件,而是重复我的代码本身。相信我,我有更多的计算,我必须在速度代码中重复这些代码多种类型。这变得一团糟。因为,如果我必须在公式中做一点小改动,我必须对速度模板中的所有重复代码进行更改,如果我们错过了重复代码中的更改,这肯定会导致人为错误。

这就是为什么我想在 Java 类中编写这些公式和计算,并在 .drl 中简单地调用该类。所以.drl.vm

.drl

import com.package.util.RuleUtil;

rule "Rule %"
no-loop
salience 10

when
    $ruleUtil: RuleUtil()
    $var: Map( this["Key"] == "SomeValue" )
then
    $ruleUtil.discountPer($var);
end

rule "Rule Amt"
no-loop
salience 9

when
    $ruleUtil: RuleUtil()
    $var: Map( this["Key"] == "SomeValue" )
then
    $ruleUtil.discountAmt($var);
end

rule "Rule % Amt"
no-loop
salience 8

when
    $ruleUtil: RuleUtil()
    $var: Map( this["Key"] == "SomeValue" )
then
    $ruleUtil.discountPer($var);
    $ruleUtil.discountAmt($var);
end

.vm

#set($d = "$")

rule "$rule.name $rule.type"
no-loop
salience $rule.priority

when
    ${d}ruleUtil: RuleUtil()
    ${d}var: Map( this["$rule.keyName"] == "$rule.keyValue" )
then
    #if( $rule.type == "%" )
        ${d}ruleUtil.discountPer(${d}var);
    #elseif( $rule.type == "Amt" )
        ${d}ruleUtil.discountAmt(${d}var);
    #elseif( $rule.type == "% Amt" )
        ${d}ruleUtil.discountPer(${d}var);
        ${d}ruleUtil.discountAmt(${d}var);
    #end

如果您想知道我重复了多少次折扣公式代码,我会说至少 10 次,并且对于多种类型的折扣计算涉及更多的重复。 TBH,当我看到.vm 代码时,我很生气。因为从长远来看,所有这些代码重复和可维护性差。我想知道是否坚持使用当前代码(当前 vm 代码涉及多个代码重复且难以维护)或者我是否应该通过实现我提出的结构将所有这些公式计算移至 Java 方法。我不知道它会对我的.drl 文件性能产生多大影响。任何建议将不胜感激。

注意:我最喜欢代码可维护性。我不希望有人在他接手这个项目后打破他的脑袋。当然,我也不想在做任何小的改变时伤脑筋。

【问题讨论】:

    标签: java performance drools velocity code-maintainability


    【解决方案1】:

    您一开始还没有提出使用模板的理由。可能是您选择了第二好的开始方法。

    也就是说,我的意见(基于大量使用模板,虽然不是为了生成 DRL)是使模板逻辑尽可能简单。我不会将任何公式放入模板中 - 坚持使用(静态)RuleUtil 方法。

    请注意,您不需要将 RuleUtil 作为事实 - 您可以通过导入类来引用其静态方法。

    即使是最后一个 tmeplate 中的简单 if-elsif 语句,我也会尽量避免。鉴于规则类型可能是 Amount、Percent 和 PercentAmount 之一,您可以编写

    rule "$rule.name $rule.type"
    when
        ${d}var: Map( this["$rule.keyName"] == "$rule.keyValue" )
    then
        ${d}ruleUtil.discount$rule.type(${d}var);
    #end
    

    我省略了显着性和无循环:我看不出第二个的原因,而第一个对于此类规则几乎总是一个坏主意。

    最后:我不喜欢 Map 作为一个事实 - 但也许有一个很好的理由不使用 bean 样式的事实类。

    【讨论】:

    • 感谢您的意见。我有一个小小的疑问。我的口水是动态形成的。所以我不知道when 中可以存在多少事实。就像我可能有$var: Map() , $var1: Map(), $var2: Map() and so on.. 有什么办法可以得到when 中声明的事实列表,我的意思是我想要所有的列表在then 中提供的事实。
    • 如果生成器能够为 LHS 生成列表,它肯定应该能够在 RHS 上执行相同的操作。如果您在 java.util.List 中需要它们,那么您拥有所有的 Java 功能。但似乎这是另一个问题。
    猜你喜欢
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多