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

让我们假设一个简单的条件

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放在这两个条件中来消除。但这只是一个例子。

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

这就是为什么我考虑在Java类中编写这些公式和计算,然后在|| $rule.type == "% Amt"中简单地对该类进行调用的原因。所以.drl.drl

.vm

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


.drl

#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方法。我不知道它将对我的.vm文件性能产生多大影响。任何建议将不胜感激。

注意:我最喜欢代码的可维护性。我不希望有人接手这个项目后摔个头。当然,我也不想在做任何小小的改变的时候break头。

最佳答案

首先,您并没有考虑使用模板。可能是您选择了第二好的方法。

就是说,我的观点(虽然不是为了生成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风格的事实类。

09-30 08:53