drools 决策表
正如我在之前的文章中所展示的那样,
JBoss Drools是一个非常有用的规则引擎
。 唯一的问题是,对于非技术人员而言,以Rule语言创建规则可能会非常复杂。 这就是为什么人们可以提供一种简便的方法来创建业务规则-在电子表格中创建决策表!
在下面的示例中,我将向您展示一个非常复杂的业务规则示例,该示例已转换为电子表格中的决策表。 作为后端,我们将有Drools,Camel和Spring。首先,让我们看一下我们想象中的业务问题。 让我们假设我们经营一家专注于销售产品(医疗或电子产品)的业务。 我们将产品运输到几个国家(PL,美国,GER,SWE,英国,ESP),并且根据国家/地区,存在不同的法律法规
关于买方的年龄。 在某些国家/地区,您可以比其他国家/地区年轻的时候购买产品。 更重要的是,取决于购买者和产品所来自的国家/地区以及产品的数量,购买者可能会获得折扣。 如您所见,在这种情况下,要实现全域需要大量条件(想象对它进行编程所需的if数量)。
另一个问题是业务方面(与往常一样)。 任何从事项目工作的人都知道需求变化的速度。 如果一个人在代码中输入了所有规则,则每次需求更改时,他都必须重新部署该软件。 因此,将业务逻辑与代码本身分开是一个好习惯。 无论如何,让我们回到例子。 首先,让我们看一下电子表格(在值得一看的
JBoss网站上,对决策表的外观进行精确描述之前
):我们程序的入口是第一个检查电子表格的地方。如果应授予给定用户购买产品的可能性(最好是下载电子表格并从Too Much Coding的Bitbucket存储库中使用电子表格:
user_table.xls
和
product_table.xls
或Github
user_table.xls
和
product_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.grzejszczczak.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有任何经验,请随时发表评论-让我们进行讨论。 所有代码都可以从
Bitbucket
和
GitHub的
Too Much Coding存储库中获得。
翻译自:
https://www.javacodegeeks.com/2013/04/drools-decision-tables-with-camel-and-spring.html
drools 决策表