drools_骆驼和春天的Drools决策表

drools

drools

正如我在之前的文章中所展示的那样, JBoss Drools是一个非常有用的规则引擎。 唯一的问题是,对于非技术人员而言,以Rule语言创建规则可能会非常复杂。 这就是为什么可以提供一种简单的方法来创建业务规则的方法-在电子表格中创建决策表!

在下面的示例中,我将向您展示一个非常复杂的业务规则示例,该示例已转换为电子表格中的决策表。 作为后端,我们将有Drools,Camel和Spring。首先,让我们看一下我们想象中的业务问题。 让我们假设我们经营一家专注于销售产品(医疗或电子产品)的业务。 我们将产品运送到多个国家(PL,美国,GER,SWE,英国,ESP),并且根据国家/地区,存在不同的法律法规关于买方的年龄。 在某些国家/地区,您可以比其他国家/地区年轻的时候购买产品。 更重要的是,取决于购买者和产​​品所来自的国家/地区以及产品的数量,购买者可能会获得折扣。 如您所见,在这种情况下,要实现全域需要大量条件(想象对它进行编程所需的if数量)。

另一个问题是业务方面(与往常一样)。 任何从事项目工作的人都知道需求变化的速度。 如果一个人在代码中输入了所有规则,则每次更改需求时,他都必须重新部署该软件。 因此,将业务逻辑与代码本身分开是一个好习惯。 无论如何,让我们回到例子。 首先,让我们看一下电子表格(在值得一看的JBoss网站上,对决策表的外观进行精确描述之前):我们程序的入口是第一个检查电子表格的地方。如果应该授予给定的用户购买产品的可能性(最好是下载电子表格并从Bitbucket的Too Much Coding的存储库中使用电子表格: user_table.xlsproduct_table.xls或Github user_table.xlsproduct_table.xls ):

user_table.xls(表工作表)

一旦用户获得批准,他可能会获得折扣:

product_table.xls(表工作表)

product_table.xls(列出工作表)

正如您在图中看到的,业务问题非常复杂。 每行代表一个规则,每列代表一个条件。 您还记得我最近的帖子中的rules语法吗? 因此,您将了解电子表格的隐藏部分,该部分在第一行可见行的正上方:

从2到6的行代表一些固定的配置值,例如规则集,导入(您已经在最近的文章中看到了)和函数。 在第7行的下一步,您可以找到RuleTable的名称。 然后,在第8行中,在我们的场景中,您将拥有CONDITION或ACTION –换句话说,分别是LHS或rhe RHS。 行号9既表示条件中表示的类型,又表示对变量的绑定。 在第10行中,我们具有确切的LHS条件。 第11行显示列的标签。 从第12行开始,我们就有一条规则。 您可以在源代码中找到电子表格。

现在让我们看一下代码。 让我们从定义产品和用户的模式开始。

人格
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:include schemaLocation="user.xsd"/>

    <xsd:element name="Product">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="Name" type="xsd:string"/>
                <xsd:element name="Type" type="ProductType"/>
                <xsd:element name="Price" type="xsd:double"/>
                <xsd:element name="CountryOfOrigin" type="CountryType"/>
                <xsd:element name="AdditionalInfo" type="xsd:string"/>
                <xsd:element name="Quantity" type="xsd:int"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:simpleType name="ProductType">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="MEDICAL"/>
            <xsd:enumeration value="ELECTRONIC"/>
        </xsd:restriction>
    </xsd:simpleType>

</xsd:schema>

User.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:include schemaLocation="product.xsd"/>

    <xsd:element name="User">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="UserName" type="xsd:string"/>
                <xsd:element name="UserAge" type="xsd:int"/>
                <xsd:element name="UserCountry" type="CountryType"/>
                <xsd:element name="Decision" type="DecisionType"/>
                <xsd:element name="DecisionDescription" type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:simpleType name="CountryType">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="PL"/>
            <xsd:enumeration value="USA"/>
            <xsd:enumeration value="GER"/>
            <xsd:enumeration value="SWE"/>
            <xsd:enumeration value="UK"/>
            <xsd:enumeration value="ESP"/>
        </xsd:restriction>
    </xsd:simpleType>

    <xsd:simpleType name="DecisionType">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="ACCEPTED"/>
            <xsd:enumeration value="REJECTED"/>
        </xsd:restriction>
    </xsd:simpleType>

</xsd:schema>

由于我们正在使用Maven,因此我们可能会使用一个将XSD转换为Java类的插件。

pom.xml的一部分

<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.5.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>1.5</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <packageName>pl.grzejszczak.marcin.drools.decisiontable.model</packageName>
                    <schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>

多亏了这个插件,我们才可以在pl.grzejszczcz.marcin.decisiontable.model包中由JAXB类生成。 现在转到drools-context.xml文件,其中我们就Drools定义了所有必需的bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:drools="http://drools.org/schema/drools-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd">

    <!-- Grid Node identifier that is registered in the CamelContext -->
    <drools:grid-node id="node1"/>

    <drools:kbase id="productsKBase" node="node1">
        <drools:resources>
            <drools:resource type="DTABLE" source="classpath:rules/product_table.xls"/>
        </drools:resources>
    </drools:kbase>

    <drools:ksession id="productsKSession" name="productsKSession" type="stateless" kbase="productsKBase" node="node1"/>

    <drools:kbase id="usersKBase" node="node1">
        <drools:resources>
            <drools:resource type="DTABLE" source="classpath:rules/user_table.xls"/>
        </drools:resources>
    </drools:kbase>

    <drools:ksession id="usersKSession" name="usersKSession" type="stateless" kbase="usersKBase" node="node1"/>

</beans>

如您所见,与最近发布的应用程序上下文相比,存在一些差异。 首先,我们没有提供DRL文件作为知识库中的资源,而是提供了决策表(DTABLE)。 我决定传递两个单独的文件,但是您可以为一个文件提供几个工作表并访问这些工作表(通过Decisiontable-conf元素)。 另外还有一个名为node的附加元素。 我们必须选择Node接口的实现(执行,网格…),以使Camel路由正常工作,就像您在Spring应用程序上下文文件中看到的那样。

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:camel="http://camel.apache.org/schema/spring"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.8.0.xsd">

    <import resource="classpath:drools-context.xml"/>
    <!-- Show Spring where to search for the beans (in which packages) -->
    <context:component-scan base-package="pl.grzejszczak.marcin.drools.decisiontable" />

    <camel:camelContext id="camelContext">
        <camel:route id="acceptanceRoute">
            <camel:from uri="direct:acceptanceRoute"/>
            <camel:to uri="drools:node1/usersKSession"/>
        </camel:route>
        <camel:route id="discountRoute">
            <camel:from uri="direct:discountRoute"/>
            <camel:to uri="drools:node1/productsKSession"/>
        </camel:route>
    </camel:camelContext>

</beans>

如您所见,为了访问Drools Camel组件,我们必须提供一个节点,通过它我们可以访问适当的知识会话。 我们定义了两条路线-第一条路线以Drools组件结束,该组件访问用户知识会话,而另一条产品知识会话。

我们有一个称为ProductServiceImpl的ProductService接口实现,给定输入User和Product对象,它们将通过Camel的Producer模板传递到两条以Drools组件结尾的Camel路由。 该产品服务的概念是,我们首先处理用户是否可以购买该软件,然后再检查他将获得什么样的折扣。 实际上,从服务的角度来看,我们只是将对象发送出去并等待响应。 最终,我们收到了响应,我们将用户和产品传递给金融服务实施部门,该实施部门将根据用户购买的产品或在需要时拒绝其要约的价格向用户收费。

ProductServiceImpl.java
package pl.grzejszczak.marcin.drools.decisiontable.service;

import org.apache.camel.CamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import pl.grzejszczak.marcin.drools.decisiontable.model.Product;
import pl.grzejszczak.marcin.drools.decisiontable.model.User;

import static com.google.common.collect.Lists.newArrayList;

/**
 * Created with IntelliJ IDEA.
 * User: mgrzejszczak
 * Date: 14.01.13
 */
@Component("productServiceImpl")
public class ProductServiceImpl implements ProductService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class);

    @Autowired
    CamelContext camelContext;

    @Autowired
    FinancialService financialService;

    @Override
    public void runProductLogic(User user, Product product) {
        LOGGER.debug("Running product logic - first acceptance Route, then discount Route");
        camelContext.createProducerTemplate().sendBody("direct:acceptanceRoute", newArrayList(user, product));
        camelContext.createProducerTemplate().sendBody("direct:discountRoute", newArrayList(user, product));
        financialService.processOrder(user, product);
    }

}

要记住的另一件至关重要的事情是,Camel Drools组件需要Command对象作为输入。 如您所见,在主体中,我们正在发送对象列表(这些不是Command对象)。 我这样做是有目的的,因为我认为最好不要将我们的代码绑定到具体的解决方案。 如果我们发现有比Drools更好的解决方案怎么办? 我们是要更改已创建的所有代码,还是只是更改骆驼路线以指向我们的新解决方案? 这就是骆驼拥有TypeConverters的原因。 我们在这里也有我们自己的。 首先让我们看一下实现。

ProductTypeConverter.java
package pl.grzejszczak.marcin.drools.decisiontable.converter;

import org.apache.camel.Converter;
import org.drools.command.Command;
import org.drools.command.CommandFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.grzejszczak.marcin.drools.decisiontable.model.Product;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: mgrzejszczak
 * Date: 30.01.13
 * Time: 21:42
 */
@Converter
public class ProductTypeConverter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProductTypeConverter.class);

    @Converter
    public static Command toCommandFromList(List inputList) {
        LOGGER.debug("Executing ProductTypeConverter's toCommandFromList method");
        return CommandFactory.newInsertElements(inputList);
    }

    @Converter
    public static Command toCommand(Product product) {
        LOGGER.debug("Executing ProductTypeConverter's toCommand method");
        return CommandFactory.newInsert(product);
    }
}

Camel网站上有一个关于TypeConverters的很好的教程-如果您需要一些更深入的信息。 无论如何,我们正在注释我们的类和用于将不同类型相互转换的函数。 这里重要的是,我们正在向骆驼展示如何将列表和单个产品转换为Commands。 由于类型擦除,不管提供的类型如何,该方法都将起作用,这就是为什么即使我们提供产品和用户的列表,toCommandFromList函数也将被执行。 除此之外,为了使类型转换器正常工作,我们还必须在/ META-INF / services / org / apache / came / TypeConverter文件中提供类(FQN)的完全准名称。

类型转换器
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter

为了正确测试我们的功能,应该编写许多测试来验证规则。 一个很好的方法是将输入文件存储在测试资源文件夹中,然后将其传递给规则引擎,然后将结果与经过验证的输出进行比较(不幸的是,使业务部门开发这样的参考集是相当不可能的输出)。 无论如何,让我们看一下仅验证一些规则的单元测试,以及运行这些规则所产生的日志:

ProductServiceImplTest.java
package pl.grzejszczak.marcin.drools.decisiontable.service.drools;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pl.grzejszczak.marcin.drools.decisiontable.model.*;
import pl.grzejszczak.marcin.drools.decisiontable.service.ProductService;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
 * Created with IntelliJ IDEA.
 * User: mgrzejszczak
 * Date: 03.02.13
 * Time: 16:06
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class ProductServiceImplTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImplTest.class);

    @Autowired
    ProductService objectUnderTest;

    @Test
    public void testRunProductLogicUserPlUnderageElectronicCountryPL() throws Exception {
        int initialPrice = 1000;
        int userAge = 6;
        int quantity = 10;

        User user = createUser("Smith", CountryType.PL, userAge);
        Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);

        assertTrue(product.getPrice() == initialPrice);
        assertEquals(DecisionType.REJECTED, user.getDecision());
    }

    @Test
    public void testRunProductLogicUserPlHighAgeElectronicCountryPLLowQuantity() throws Exception {
        int initialPrice = 1000;
        int userAge = 19;
        int quantity = 1;

        User user = createUser("Smith", CountryType.PL, userAge);
        Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);

        assertTrue(product.getPrice() == initialPrice);
        assertEquals(DecisionType.ACCEPTED, user.getDecision());
    }

    @Test
    public void testRunProductLogicUserPlHighAgeElectronicCountryPLHighQuantity() throws Exception {
        int initialPrice = 1000;
        int userAge = 19;
        int quantity = 8;

        User user = createUser("Smith", CountryType.PL, userAge);
        Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);
        double expectedDiscount = 0.1;

        assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount));
        assertEquals(DecisionType.ACCEPTED, user.getDecision());
    }

    @Test
    public void testRunProductLogicUserUsaLowAgeElectronicCountryPLHighQuantity() throws Exception {
        int initialPrice = 1000;
        int userAge = 19;
        int quantity = 8;

        User user = createUser("Smith", CountryType.USA, userAge);
        Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);

        assertTrue(product.getPrice() == initialPrice);
        assertEquals(DecisionType.REJECTED, user.getDecision());
    }

    @Test
    public void testRunProductLogicUserUsaHighAgeMedicalCountrySWELowQuantity() throws Exception {
        int initialPrice = 1000;
        int userAge = 22;
        int quantity = 4;

        User user = createUser("Smith", CountryType.USA, userAge);
        Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);

        assertTrue(product.getPrice() == initialPrice);
        assertEquals(DecisionType.ACCEPTED, user.getDecision());
    }

    @Test
    public void testRunProductLogicUserUsaHighAgeMedicalCountrySWEHighQuantity() throws Exception {
        int initialPrice = 1000;
        int userAge = 22;
        int quantity = 8;

        User user = createUser("Smith", CountryType.USA, userAge);
        Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);

        printInputs(user, product);

        objectUnderTest.runProductLogic(user, product);

        printInputs(user, product);
        double expectedDiscount = 0.25;

        assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount));
        assertEquals(DecisionType.ACCEPTED, user.getDecision());
    }

    private void printInputs(User user, Product product) {
        LOGGER.debug(ReflectionToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
        LOGGER.debug(ReflectionToStringBuilder.reflectionToString(product, ToStringStyle.MULTI_LINE_STYLE));
    }

    private User createUser(String name, CountryType countryType, int userAge){
        User user = new User();
        user.setUserName(name);
        user.setUserCountry(countryType);
        user.setUserAge(userAge);
        return user;
    }

    private Product createProduct(String name, double price, CountryType countryOfOrigin, ProductType productType, int quantity){
        Product product = new Product();
        product.setPrice(price);
        product.setCountryOfOrigin(countryOfOrigin);
        product.setName(name);
        product.setType(productType);
        product.setQuantity(quantity);
        return product;
    }

}

当然,测试中的log.debugs完全是多余的,但是我希望您能快速看到这些规则是可行的。 很抱歉日志的长度,但是我写了一些测试来显示不同的规则组合(实际上最好有太多的日志而不是相反的方式)

pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[
  userName=Smith
  userAge=6
  userCountry=PL
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=10
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (PL) you can't buy this product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[
  userName=Smith
  userAge=6
  userCountry=PL
  decision=REJECTED
  decisionDescription=Sorry, according to your age (< 18) and country (PL) you can't buy this product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=10
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[
  userName=Smith
  userAge=19
  userCountry=PL
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=1
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, no discount will be granted.
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[
  userName=Smith
  userAge=19
  userCountry=PL
  decision=ACCEPTED
  decisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=Sorry, no discount will be granted.
  quantity=1
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[
  userName=Smith
  userAge=19
  userCountry=PL
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations - you've been granted a 10% discount!
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[
  userName=Smith
  userAge=19
  userCountry=PL
  decision=ACCEPTED
  decisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[
  name=Electronic
  type=ELECTRONIC
  price=900.0
  countryOfOrigin=PL
  additionalInfo=Congratulations - you've been granted a 10% discount!
  quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[
  userName=Smith
  userAge=19
  userCountry=USA
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (USA) you can't buy this product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[
  userName=Smith
  userAge=19
  userCountry=USA
  decision=REJECTED
  decisionDescription=Sorry, according to your age (< 18) and country (USA) you can't buy this product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[
  name=Electronic
  type=ELECTRONIC
  price=1000.0
  countryOfOrigin=PL
  additionalInfo=<null>
  quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[
  userName=Smith
  userAge=22
  userCountry=USA
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[
  name=Some name
  type=MEDICAL
  price=1000.0
  countryOfOrigin=SWE
  additionalInfo=<null>
  quantity=4
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[
  userName=Smith
  userAge=22
  userCountry=USA
  decision=ACCEPTED
  decisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[
  name=Some name
  type=MEDICAL
  price=1000.0
  countryOfOrigin=SWE
  additionalInfo=<null>
  quantity=4
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[
  userName=Smith
  userAge=22
  userCountry=USA
  decision=<null>
  decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[
  name=Some name
  type=MEDICAL
  price=1000.0
  countryOfOrigin=SWE
  additionalInfo=<null>
  quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you are granted a discount
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[
  userName=Smith
  userAge=22
  userCountry=USA
  decision=ACCEPTED
  decisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[
  name=Some name
  type=MEDICAL
  price=750.0
  countryOfOrigin=SWE
  additionalInfo=Congratulations, you are granted a discount
  quantity=8
]

在这篇文章中,我介绍了如何通过给他一个他可以使用的工具(电子表格中的决策表)来推动您的一些开发工作到BA。 而且,您现在将如何将Drools与Camel集成在一起。 希望您将看到如何简化业务规则的实现(从而将实施和支持的成本降至最低),同时牢记更改的可能性。 我希望这个例子能够比以前关于Drools的文章更好地说明用Java实现所有业务规则有多么困难 如果您在决策表,与Spring和Camel集成方面对Drools有任何经验,请随时发表评论-让我们进行讨论。 所有代码都可以在BitbucketGitHub的Too Much Coding存储库中获得。

参考:来自BCG的JCG合作伙伴Marcin Grzejszczak的Drools与Camel和Spring的决策表,用于编码成瘾者博客。

翻译自: https://www.javacodegeeks.com/2013/04/drools-decision-tables-with-camel-and-spring.html

drools

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值