21.6. pet Store 示例决策(示例组、全局变量、回调和 GUI 集成)


Pet Store 示例决策集演示了如何在规则中使用平板组和全局变量,以及如何将红帽决策管理器规则与图形用户界面(GUI)集成,在这种情况下,基于 Swing 的桌面应用程序。这个示例还演示了如何使用回调与正在运行的决策引擎交互,以在运行时根据工作内存中的更改更新 GUI。

以下是 Pet Store 示例的概述:

  • 名称petstore
  • 主类org.drools.examples.petstore.PetStoreExample (在 src/main/java中)
  • 模块drools-examples
  • 键入: Java 应用程序
  • 规则文件org.drools.examples.petstore.PetStore.drl ( src/main/resources)
  • 目标 :演示规则索引组、全局变量、回调和 GUI 集成

在 Pet Store 示例中,示例 PetStoreExample.java 类定义了以下主体类(除了多个类来处理 Swing 事件外):

  • Petstore 包含 main() 方法。
  • PetStoreUI 负责创建和显示基于 Swing 的 GUI。此类包含多个较小的类,主要用于响应各种 GUI 事件,比如鼠标点击的用户。
  • TableModel 包含表数据。这个类本质上是扩展 Swing 类 AbstractTableModel 的 JavaBean。
  • CheckoutCallback 允许 GUI 与规则交互。
  • Ordershow 保留您要购买的项目。
  • 购买 存储订购详情以及您要购买的产品。
  • 产品是 JavaBean,其中包含可供购买的产品及其价格的详细信息。

本例中的大部分 Java 代码是基于普通 JavaBean 或 Swing。有关 Swing 组件的更多信息,请参阅有关 使用 JFC/Swing 创建 GUI 的 Java 教程。

Pet Store 示例中的规则执行行为

与其他示例决定设置被断言并立即触发,Pet Store 示例不会执行规则,直到根据用户交互收集更多事实。这个示例通过构造器创建的 PetStoreUI 对象来执行规则,接受 Vector 对象 库存 来收集该产品。然后,示例使用 Checkout Callback 类的实例,其中包含之前载入的规则基础。

pet Store KIE 容器和事实执行设置

// KieServices is the factory for all KIE services.
KieServices ks = KieServices.Factory.get();

// Create a KIE container on the class path.
KieContainer kc = ks.getKieClasspathContainer();

// Create the stock.
Vector<Product> stock = new Vector<Product>();
stock.add( new Product( "Gold Fish", 5 ) );
stock.add( new Product( "Fish Tank", 25 ) );
stock.add( new Product( "Fish Food", 2 ) );

// A callback is responsible for populating the working memory and for firing all rules.
PetStoreUI ui = new PetStoreUI( stock,
                                new CheckoutCallback( kc ) );
ui.createAndShowGUI();
Copy to Clipboard Toggle word wrap

触发规则的 Java 代码位于 CheckoutCallBack.checkout() 方法中。当用户在 UI 中点击 Checkout 时触发 此方法。

来自 CheckoutCallBack.checkout()的规则执行

public String checkout(JFrame frame, List<Product> items) {
    Order order = new Order();

    // Iterate through list and add to cart.
    for ( Product p: items ) {
        order.addItem( new Purchase( order, p ) );
    }

    // Add the JFrame to the ApplicationData to allow for user interaction.

    // From the KIE container, a KIE session is created based on
    // its definition and configuration in the META-INF/kmodule.xml file.
    KieSession ksession = kcontainer.newKieSession("PetStoreKS");

    ksession.setGlobal( "frame", frame );
    ksession.setGlobal( "textArea", this.output );

    ksession.insert( new Product( "Gold Fish", 5 ) );
    ksession.insert( new Product( "Fish Tank", 25 ) );
    ksession.insert( new Product( "Fish Food", 2 ) );

    ksession.insert( new Product( "Fish Food Sample", 0 ) );

    ksession.insert( order );

    // Execute rules.
    ksession.fireAllRules();

    // Return the state of the cart
    return order.toString();
}
Copy to Clipboard Toggle word wrap

示例代码将两个元素传递给 CheckoutCallBack.checkout() 方法。一个元素是处理 JFrame Swing 组件,位于 GUI 的底部。第二个元素是顺序项目的列表,它来自 GUI 右上角的表格区域的信息。

for 循环将来自于 GUI 的订购项列表转换为 Order JavaBean,同时包含在文件 PetStoreExample.java 中。

在这种情况下,规则会在无状态 KIE 会话中触发,因为所有数据都存储在 Swing 组件中,并在用户点击 UI 中的 Checkout 之前执行。每次用户点击 Checkout 时,列表的内容都会从 Swing TableModel 移到 KIE 会话工作内存中,然后使用 ksession.fireAllRules() 方法执行。

在此代码中,对 KieSession 有 9 个调用。其中之一从 KieContainer 创建新的 KieSession (在这个 KieContainer 中通过的示例从 main() 方法中的 CheckoutCallBack 类传递)。接下来的两个调用通过规则中存放全局变量的两个对象: Swing 文本区域以及用于编写消息的 Swing 帧。并将有关产品的信息插入 KieSession 以及顺序列表中的更多信息。最终的调用是标准 fireAllRules()

pet Store 规则文件导入、全局变量和 Java 功能

PetStore.drl 文件包含标准软件包和导入语句,以使规则可以使用各种 Java 类。规则文件还包括用于在规则(定义为 textArea )中使用的 全局变量。全局变量包含对之前由称为 setGlobal() 方法的 Java 代码传递的 Swing 组件 JFrameJTextArea 组件的引用。与规则中的标准变量不同,在规则触发后,全局变量会保留其在 KIE 会话生命周期中的值。这意味着这些全局变量的内容可以对所有后续规则进行评估。

PetStore.drl 软件包、导入和全局变量

package org.drools.examples;

import org.kie.api.runtime.KieRuntime;
import org.drools.examples.petstore.PetStoreExample.Order;
import org.drools.examples.petstore.PetStoreExample.Purchase;
import org.drools.examples.petstore.PetStoreExample.Product;
import java.util.ArrayList;
import javax.swing.JOptionPane;

import javax.swing.JFrame;

global JFrame frame
global javax.swing.JTextArea textArea
Copy to Clipboard Toggle word wrap

PetStore.drl 文件还包含两个使用中的规则:

PetStore.drl Java 功能

function void doCheckout(JFrame frame, KieRuntime krt) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to checkout?",
                                             "",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       if (n == 0) {
            krt.getAgenda().getAgendaGroup( "checkout" ).setFocus();
       }
}

function boolean requireTank(JFrame frame, KieRuntime krt, Order order, Product fishTank, int total) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to buy a tank for your " + total + " fish?",
                                             "Purchase Suggestion",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       System.out.print( "SUGGESTION: Would you like to buy a tank for your "
                           + total + " fish? - " );

       if (n == 0) {
             Purchase purchase = new Purchase( order, fishTank );
             krt.insert( purchase );
             order.addItem( purchase );
             System.out.println( "Yes" );
       } else {
            System.out.println( "No" );
       }
       return true;
}
Copy to Clipboard Toggle word wrap

这两个功能执行以下操作:

  • doCheckout() 显示一个对话框,它要求用户是否被委派或需要签出。如果用户确实如此,则重点设置为 结账 员组,使该组中的规则启用(可能)触发。
  • requireTank() 会显示一个对话框,该对话框要求用户如果她或想要购买财务语。如果用户确实有,则会在工作内存中的订购列表中添加一个新芬兰的 tank 产品
注意

在本例中,所有规则和功能都位于同一个规则文件中,以提高效率。在生产环境中,您通常将不同文件中的规则和功能分开,或构建静态 Java 方法并使用导入功能导入文件,如 导入功能 my.package.name.hello

pet Store 规则与日程组

Pet Store 示例中的大多数规则使用 table 组来控制规则执行。日程表组允许您对决策引擎日程表进行分区,以便对规则组提供更多执行控制。默认情况下,所有规则均位于 MAIN 日程小组。您可以使用 schedule -group 属性来指定该规则的不同日程表组。

最初,工作内存专注于 MAIN 的日程安排。仅当该组收到相关事项时,即可参与日程表组中的规则。您可以使用方法 setFocus() 或 rule 属性 auto-focus 来设置焦点。auto-focus 属性允许当规则匹配和激活时,自动为课程安排人员自动给定规则。

Pet Store 示例对规则使用以下日程组:

  • "init"
  • "评估"
  • "显示项目"
  • "checkout"

例如,示例规则 "Explode Cart" 使用 "init" 资格将 cart 项目触发并插入到 KIE 会话工作内存中:

规则"Explode Cart"

// Insert each item in the shopping cart into the working memory.
rule "Explode Cart"
    agenda-group "init"
    auto-focus true
    salience 10
  when
    $order : Order( grossTotal == -1 )
    $item : Purchase() from $order.items
  then
    insert( $item );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "show items" ).setFocus();
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "evaluate" ).setFocus();
end
Copy to Clipboard Toggle word wrap

该规则与所有尚未计算的订单匹配。每个购买项目的执行循环按该顺序排列。

该规则使用与其 schedule 组相关的以下功能:

  • 日程表组"init" 定义日程表组的名称。在这种情况下,组中只有一个规则。但是,Java 代码和规则都无法专注于此组,因此它也取决于其触发的机会的 auto-focus 属性。
  • auto-focus true 可确保此规则,而作为 schedule group 中的唯一规则,但从 Java 代码调用 fireAllRules() 时有机会触发。
  • kcontext…​.setFocus() 将焦点设置为 "show items""evaluate" 日程表组,支持他们触发的规则。在实践中,您要循环顺序的所有项目,将它们插入到内存中,然后在各个插入后触发其他规则。

"显示项目" 日程表组仅包含一条规则,"项目方式"对于当前 KIE 会话工作内存顺序的每个购买,规则会根据规则文件中定义的文本区域将详情记录到 GUI 底部的文本区域。

规则"显示方式"

rule "Show Items"
    agenda-group "show items"
  when
    $order : Order()
    $p : Purchase( order == $order )
  then
   textArea.append( $p.product + "\n");
end
Copy to Clipboard Toggle word wrap

"评估" 日程表组还从 "Explode Cart" 规则获得。此日程表组包含两个规则 :"Free Fish Food Sample""Suggest Tank",按该顺序执行。

规则"Free Fish Food Sample"

// Free fish food sample when users buy a goldfish if they did not already buy
// fish food and do not already have a fish food sample.
rule "Free Fish Food Sample"
    agenda-group "evaluate" 
1

  when
    $order : Order()
    not ( $p : Product( name == "Fish Food") && Purchase( product == $p ) ) 
2

    not ( $p : Product( name == "Fish Food Sample") && Purchase( product == $p ) ) 
3

    exists ( $p : Product( name == "Gold Fish") && Purchase( product == $p ) ) 
4

    $fishFoodSample : Product( name == "Fish Food Sample" );
  then
    System.out.println( "Adding free Fish Food Sample to cart" );
    purchase = new Purchase($order, $fishFoodSample);
    insert( purchase );
    $order.addItem( purchase );
end
Copy to Clipboard Toggle word wrap

只有在以下条件都满足时,才会触发 "Free Fish Food Sample" 规则:

1
日程组 "评估" 在规则执行中评估。
2
用户还没有 fish food。
3
用户还没有一个自由的页式示例。
4
用户按数字顺序使用 goldfish。

如果顺序事实满足所有这些要求,则创建一个新产品(Fish Food Sample)并添加到工作内存中的顺序中。

规则"Suggest Tank"

// Suggest a fish tank if users buy more than five goldfish and
// do not already have a tank.
rule "Suggest Tank"
    agenda-group "evaluate"
  when
    $order : Order()
    not ( $p : Product( name == "Fish Tank") && Purchase( product == $p ) ) 
1

    ArrayList( $total : size > 5 ) from collect( Purchase( product.name == "Gold Fish" ) ) 
2

    $fishTank : Product( name == "Fish Tank" )
  then
    requireTank(frame, kcontext.getKieRuntime(), $order, $fishTank, $total);
end
Copy to Clipboard Toggle word wrap

只有在以下条件满足时才触发 "Suggest Tank" 规则:

1
用户没有按顺序的ish tank。
2
用户按以下顺序排列,有五种种。

当规则触发时,它会调用规则 文件中定义的 requireTank() 函数。此函数会显示一个对话框,询问用户是否是她或他想要购买玻里程表。如果用户确实有,则会在工作内存中的订购列表中添加一个新芬兰的 tank 产品。当规则调用 requireTank() 函数时,该规则会传递帧的全局变量,以便该函数能够处理 Swing GUI。

Pet Store 示例中的 "do checkout" 规则没有日程表组,没有条件,因此该规则始终执行并被视为默认 MAIN 更新组的一部分。

规则 "do checkout"

rule "do checkout"
  when
  then
    doCheckout(frame, kcontext.getKieRuntime());
end
Copy to Clipboard Toggle word wrap

当规则触发时,它会调用规则 文件中定义的 doCheckout() 函数。此函数显示一个对话框,询问用户是否她或他想要签出。如果用户确实如此,则重点设置为 结账 员组,使该组中的规则启用(可能)触发。当规则调用 doCheckout() 函数时,该规则会传递 全局变量,以便该函数能够处理 Swing GUI。

注意

本例还演示了故障排除技术(如果结果未按预期一样执行):您可以从规则的 when 语句中删除条件,并在 then 语句中测试操作以验证操作是否正确执行。

"检查" 日程表组包含三个规则,用于处理订单并申请任何折扣:" 总额"、" 应用 5% 的折扣""应用 10% 的折扣 "。

规则"总额"、"Apply 5% 的折扣"和"Apply 10% 的折扣"

rule "Gross Total"
    agenda-group "checkout"
  when
    $order : Order( grossTotal == -1)
    Number( total : doubleValue ) from accumulate( Purchase( $price : product.price ),
                                                              sum( $price ) )
  then
    modify( $order ) { grossTotal = total }
    textArea.append( "\ngross total=" + total + "\n" );
end

rule "Apply 5% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 10 && < 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.95;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

rule "Apply 10% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.90;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end
Copy to Clipboard Toggle word wrap

如果用户还没有计算总额的单位,Grossing Total accate the product 总计(将总值放在 KIE 会话中),并使用 textArea global 变量通过 Swing JTextArea 显示它。

如果总额介于 1020 左右,则 "Apply 5% discount" 规则计算总折扣,将其添加到 KIE 会话中,并将其显示在文本区域中。

如果总总额不低于 20"Apply 10% discount" 规则计算总额,将其添加到 KIE 会话中,并在文本区域中显示它。

pet Store 的执行示例

与其他红帽决策管理器决策示例类似,您可以通过运行 org.drools.examples.petstore.PetStoreExample 类作为 IDE 中的 Java 应用程序来执行 Pet Storeample 类。

当您执行 Pet Store 示例时,会显示 Pet Store Demo GUI 窗口。此窗口显示可用产品列表(左下)、选定产品的空列表(右、CheckoutReset 按钮(middle))和一个空系统消息区域(bottom)。

图 21.14. 启动后 pet Store 示例 GUI

本例中发生以下事件来建立此执行行为:

  1. main() 方法已运行并加载规则基础,但尚未触发规则。目前,这是与运行的规则连接中的唯一代码。
  2. 新的 PetStoreUI 对象已创建,并为规则基础赋予句柄,供以后使用。
  3. 各种 Swing 组件已执行其功能,并显示初始 UI 屏幕并等待用户输入。

您可以从列表中点各种产品以浏览 UI 设置:

图 21.15. 探索 Pet Store 示例 GUI

还没有触发规则代码。UI 使用 Swing 代码来检测用户鼠标点击并将所选产品添加到用于 UI 右上角显示的 TableModel 对象中。本例演示了 Model-View-Controller 设计模式。

当您点 Checkout 时,规则会按以下方式触发:

  1. CheckOutCallBack.checkout() 方法由 Swing 类调用(事件),等待用户点击 Checkout。这会将 TableModel 对象(UI 右上角)中的数据插入到 KIE 会话工作内存中。然后,该方法会触发规则。
  2. "Explode Cart" 规则是第一个触发,auto-focus 属性设为 true。通过 cart 中的所有产品的规则循环,确保产品处于工作内存中,然后提供 "显示项目"和" 评估" 日程表组来触发的选项。这些组中的规则将 cart 的内容添加到文本区域(bottom)中,评估您是否有资格获得免费的放大分,并确定是否希望购买欺诈。

    图 21.16. 芬兰 tank 资格

  3. "do checkout" 规则是下一个需要触发的,因为其他任何日程组当前没有关注,因为它是默认的 MAIN 日程小组的一部分。这个规则始终调用 doCheckout() 函数,它会询问您是否要签出。
  4. doCheckout() 函数将焦点设置为 "checkout" Table 组,该组中的规则给出了要触发的选项。
  5. "检查" 日程表组中的规则显示车队的内容,并应用相应的折扣。
  6. 然后,等待用户输入可选择更多产品(并导致规则再次触发),或关闭 UI。

    图 21.17. 所有规则触发后的 pet Store 示例 GUI

您可以添加更多 System.out 调用来在 IDE 控制台中演示此事件流:

IDE 控制台中的 system.out 输出

Adding free Fish Food Sample to cart
SUGGESTION: Would you like to buy a tank for your 6 fish? - Yes
Copy to Clipboard Toggle word wrap

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat