骆驼和春天的Drools决策表
正如我在之前的文章中所展示的那樣, JBoss Drools是一個(gè)非常有用的規(guī)則引擎 。 唯一的問(wèn)題是,對(duì)于非技術(shù)人員而言,以Rule語(yǔ)言創(chuàng)建規(guī)則可能會(huì)非常復(fù)雜。 這就是為什么可以提供一種輕松的方式來(lái)創(chuàng)建業(yè)務(wù)規(guī)則的方法-在電子表格中創(chuàng)建決策表!
在以下示例中,我將向您展示一個(gè)非常復(fù)雜的業(yè)務(wù)規(guī)則示例,該示例已轉(zhuǎn)換為電子表格中的決策表。 作為后端,我們將有Drools,Camel和Spring。首先,讓我們看一下我們想象中的業(yè)務(wù)問(wèn)題。 讓我們假設(shè)我們經(jīng)營(yíng)一家專(zhuān)注于銷(xiāo)售產(chǎn)品(醫(yī)療或電子產(chǎn)品)的業(yè)務(wù)。 我們將產(chǎn)品運(yùn)送到多個(gè)國(guó)家(PL,美國(guó),GER,SWE,英國(guó),ESP),并且根據(jù)國(guó)家/地區(qū),存在不同的法律法規(guī)
關(guān)于買(mǎi)方的年齡。 在某些國(guó)家/地區(qū),您可以比其他國(guó)家/地區(qū)年輕的時(shí)候購(gòu)買(mǎi)產(chǎn)品。 更重要的是,取決于購(gòu)買(mǎi)者和產(chǎn)??品所來(lái)自的國(guó)家/地區(qū)以及產(chǎn)品的數(shù)量,購(gòu)買(mǎi)者可能會(huì)獲得折扣。 如您所見(jiàn),在這種情況下,要實(shí)現(xiàn)全域需要大量條件(想象對(duì)它進(jìn)行編程所需的if數(shù)量)。
另一個(gè)問(wèn)題是業(yè)務(wù)方面(與往常一樣)。 任何從事項(xiàng)目工作的人都知道需求變化的速度。 如果一個(gè)人在代碼中輸入了所有規(guī)則,則每次需求更改時(shí),他都必須重新部署該軟件。 因此,將業(yè)務(wù)邏輯與代碼本身分開(kāi)是一個(gè)好習(xí)慣。 無(wú)論如何,讓我們回到我們的示例。 首先,讓我們看一下電子表格(在值得一看的JBoss網(wǎng)站上,對(duì)決策表的外觀進(jìn)行精確描述之前 ):我們程序的入口是第一個(gè)檢查電子表格的地方。如果應(yīng)授予給定用戶購(gòu)買(mǎi)產(chǎn)品的可能性(最好是下載電子表格并從Too Much Coding的Bitbucket倉(cāng)庫(kù)中下載電子表格并使用它們: user_table.xls和product_table.xls或Github user_table.xls和product_table.xls ):
user_table.xls(表工作表)
用戶獲得批準(zhǔn)后,他可能會(huì)獲得折扣:
product_table.xls(表工作表)
product_table.xls(列出工作表)
正如您在圖中看到的,業(yè)務(wù)問(wèn)題非常復(fù)雜。 每行代表一個(gè)規(guī)則,每列代表一個(gè)條件。 您還記得我最近的帖子中的rules語(yǔ)法嗎? 因此,您將了解電子表格的隱藏部分,該部分位于第一行可見(jiàn)的上方:
從2到6的行代表一些固定的配置值,例如規(guī)則集,導(dǎo)入( 您已經(jīng)在最近的文章中看到了 )和函數(shù)。 在第7行中,您可以找到RuleTable的名稱(chēng)。 然后在第8行中,在我們的場(chǎng)景中,您將具有CONDITION或ACTION –換句話說(shuō),分別是LHS或rhe RHS。 行號(hào)9既表示條件中表示的類(lèi)型,又表示對(duì)變量的綁定。 在第10行中,我們具有確切的LHS條件。 第11行顯示列的標(biāo)簽。 從第12行開(kāi)始,我們就有一條規(guī)則。 您可以在源代碼中找到電子表格。
現(xiàn)在讓我們看一下代碼。 讓我們從定義產(chǎn)品和用戶的模式開(kāi)始。
人格
<?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,因此我們可能會(huì)使用一個(gè)將XSD轉(zhuǎn)換為Java類(lèi)的插件。
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>多虧了這個(gè)插件,我們才能在pl.grzejszczczak.marcin.decisiontable.model包中由JAXB類(lèi)生成。 現(xiàn)在轉(zhuǎn)到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.xsdhttp://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>如您所見(jiàn),與最近發(fā)布的應(yīng)用程序上下文相比,存在一些差異。 首先,我們沒(méi)有提供DRL文件作為知識(shí)庫(kù)中的資源,而是提供了決策表(DTABLE)。 我決定傳遞兩個(gè)單獨(dú)的文件,但是您可以為一個(gè)文件提供幾個(gè)工作表并訪問(wèn)這些工作表(通過(guò)Decisiontable-conf元素)。 另外還有一個(gè)名為node的附加元素。 我們必須選擇Node接口的實(shí)現(xiàn)(Execution,Grid…),Camel路由才能正常工作,就像您在Spring應(yīng)用程序上下文文件中看到的那樣。
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.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://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>如您所見(jiàn),為了訪問(wèn)Drools Camel組件,我們必須提供一個(gè)節(jié)點(diǎn),通過(guò)它我們可以訪問(wèn)適當(dāng)?shù)闹R(shí)會(huì)話 。 我們定義了兩條路線-第一條路線終止于Drools組件,該組件訪問(wèn)用戶知識(shí)會(huì)話,而另一條產(chǎn)品知識(shí)會(huì)話。
我們有一個(gè)稱(chēng)為ProductServiceImpl的ProductService接口實(shí)現(xiàn),給定輸入U(xiǎn)ser和Product對(duì)象,它們將通過(guò)Camel的Producer模板傳遞到兩條以Drools組件結(jié)尾的Camel路由。 該產(chǎn)品服務(wù)的概念是,我們首先處理用戶是否可以購(gòu)買(mǎi)該軟件,然后再檢查他將獲得什么樣的折扣。 實(shí)際上,從服務(wù)的角度來(lái)看,我們只是將對(duì)象發(fā)送出去并等待響應(yīng)。 最終,我們收到了響應(yīng),我們將用戶和產(chǎn)品傳遞給金融服務(wù)實(shí)施部門(mén),該實(shí)施部門(mén)將根據(jù)用戶購(gòu)買(mǎi)的產(chǎn)品或在需要時(shí)拒絕其要約的價(jià)格向用戶收費(fèi)。
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);@AutowiredCamelContext camelContext;@AutowiredFinancialService financialService;@Overridepublic 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);}}要記住的另一件至關(guān)重要的事情是,Camel Drools組件需要Command對(duì)象作為輸入。 如您所見(jiàn),在主體中,我們正在發(fā)送對(duì)象列表(這些不是Command對(duì)象)。 我這樣做是有目的的,因?yàn)槲艺J(rèn)為最好不要將我們的代碼綁定到具體的解決方案。 如果我們發(fā)現(xiàn)有比Drools更好的解決方案怎么辦? 我們是要更改已創(chuàng)建的所有代碼,還是只是更改駱駝路線以指向我們的新解決方案? 這就是駱駝?chuàng)碛蠺ypeConverters的原因。 我們?cè)谶@里也有我們自己的。 首先讓我們看一下實(shí)現(xiàn)。
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);@Converterpublic static Command toCommandFromList(List inputList) {LOGGER.debug("Executing ProductTypeConverter's toCommandFromList method");return CommandFactory.newInsertElements(inputList);}@Converterpublic static Command toCommand(Product product) {LOGGER.debug("Executing ProductTypeConverter's toCommand method");return CommandFactory.newInsert(product);} }在Camel網(wǎng)站上有一個(gè)關(guān)于TypeConverters的很好的教程–如果您需要一些更深入的信息。 無(wú)論如何,我們都在注釋我們的類(lèi)和用于將不同類(lèi)型相互轉(zhuǎn)換的函數(shù)。 這里重要的是,我們正在向駱駝?wù)故救绾螌⒘斜砗蛦蝹€(gè)產(chǎn)品轉(zhuǎn)換為Commands。 由于類(lèi)型擦除,不管提供的類(lèi)型如何,該方法都將起作用,這就是為什么即使我們提供了產(chǎn)品和用戶列表,toCommandFromList函數(shù)也將被執(zhí)行。 除此之外,為了使類(lèi)型轉(zhuǎn)換器正常工作,我們還必須在/ META-INF / services / org / apache / came / TypeConverter文件中提供類(lèi)的完整名稱(chēng)(FQN)。
類(lèi)型轉(zhuǎn)換器
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter為了正確測(cè)試我們的功能,應(yīng)該編寫(xiě)很多測(cè)試來(lái)驗(yàn)證規(guī)則。 相當(dāng)不錯(cuò)的方法是將輸入文件存儲(chǔ)在測(cè)試資源文件夾中,然后將其傳遞給規(guī)則引擎,然后將結(jié)果與經(jīng)過(guò)驗(yàn)證的輸出進(jìn)行比較(不幸的是,使業(yè)務(wù)部門(mén)開(kāi)發(fā)這樣的參考集是相當(dāng)不可能的輸出)。 無(wú)論如何,讓我們看一下僅驗(yàn)證一些規(guī)則的單元測(cè)試以及運(yùn)行這些規(guī)則所產(chǎn)生的日志:
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);@AutowiredProductService objectUnderTest;@Testpublic 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());}@Testpublic 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());}@Testpublic 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());}@Testpublic 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());}@Testpublic 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());}@Testpublic 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;}}當(dāng)然,測(cè)試中的log.debugs完全是多余的,但是我希望您能快速看到這些規(guī)則是可行的。 很抱歉記錄的長(zhǎng)度,但是我寫(xiě)了一些測(cè)試來(lái)顯示不同的規(guī)則組合(實(shí)際上最好有太多的記錄而不是相反的記錄)
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[userName=SmithuserAge=6userCountry=PLdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<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=SmithuserAge=6userCountry=PLdecision=REJECTEDdecisionDescription=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=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=10 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[userName=SmithuserAge=19userCountry=PLdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<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=SmithuserAge=19userCountry=PLdecision=ACCEPTEDdecisionDescription=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=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=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=SmithuserAge=19userCountry=PLdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<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=SmithuserAge=19userCountry=PLdecision=ACCEPTEDdecisionDescription=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=Electronictype=ELECTRONICprice=900.0countryOfOrigin=PLadditionalInfo=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=SmithuserAge=19userCountry=USAdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<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=SmithuserAge=19userCountry=USAdecision=REJECTEDdecisionDescription=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=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[userName=SmithuserAge=22userCountry=USAdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[name=Some nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<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=SmithuserAge=22userCountry=USAdecision=ACCEPTEDdecisionDescription=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 nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<null>quantity=4 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[userName=SmithuserAge=22userCountry=USAdecision=<null>decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[name=Some nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<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=SmithuserAge=22userCountry=USAdecision=ACCEPTEDdecisionDescription=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 nametype=MEDICALprice=750.0countryOfOrigin=SWEadditionalInfo=Congratulations, you are granted a discountquantity=8 ] 在這篇文章中,我介紹了如何通過(guò)給他一個(gè)他可以使用的工具(電子表格中的決策表)來(lái)將您的一些開(kāi)發(fā)工作推向BA。 而且,您現(xiàn)在將如何將Drools與Camel集成。 希望您會(huì)看到如何簡(jiǎn)化業(yè)務(wù)規(guī)則的實(shí)現(xiàn)(從而將實(shí)施和支持的成本降至最低),同時(shí)牢記更改的可能性。 我希望這個(gè)示例能夠比以前關(guān)于Drools的文章更好地說(shuō)明用Java實(shí)現(xiàn)所有業(yè)務(wù)規(guī)則將有多么困難。 如果您在決策表,與Spring和Camel的集成方面對(duì)Drools有任何經(jīng)驗(yàn),請(qǐng)隨時(shí)發(fā)表評(píng)論-讓我們進(jìn)行討論。 所有代碼都可以在Bitbucket和GitHub的 Too Much Coding存儲(chǔ)庫(kù)中獲得。
翻譯自: https://www.javacodegeeks.com/2013/04/drools-decision-tables-with-camel-and-spring.html
總結(jié)
以上是生活随笔為你收集整理的骆驼和春天的Drools决策表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux 内核驱动(linux驱动内核
- 下一篇: 了解播放过滤器API