本文用Drools 解决喝啤酒问题。
本文结构如下:
1. 规则
2. 通过业务式编程 实现
3. 通过drools 规则引擎实现
规则:
//喝啤酒问题,小明去喝啤酒,啤酒搞活动,
// 啤酒二元一瓶,
// 两个空瓶可以再换一瓶啤酒,
// 四个瓶盖也可以换一瓶啤酒,
// 问小明花多少钱可以喝多少瓶啤酒?
通过业务式编程。代码实现:
public class DrinkBeerTest {
public static void main(String[] args) {
System.out.println("请输入买啤酒的总金额:");
Scanner sc = new Scanner(System.in);
int money = sc.nextInt();
int drinkSum = 0, blankCup = 0, cap = 0;
//drinkSum:喝的瓶数
drinkSum = money / 2;
//cap:瓶盖数 ,blankCup:空瓶数
cap = blankCup = drinkSum;
while (cap / 4 >= 1 || blankCup / 2 >= 1) {
if (blankCup / 2 >= 1)//计算瓶子
{
drinkSum += blankCup / 2;
cap = cap + blankCup / 2;
blankCup = blankCup % 2 + blankCup / 2;
}
if (cap / 4 >= 1) { //计算瓶盖
drinkSum += cap / 4;
blankCup += cap / 4;
cap = cap % 4 + cap / 4;
}
}
System.out.println("总共喝啤酒数" + drinkSum + " 剩余空瓶数:" + blankCup + " 剩余瓶盖数:" + cap);
}
}
结语:代码嵌套层次多,复杂,语义晦涩难懂,不便理解。且规则变化,可复用性低。
3. 通过Drools 实现
3.1 pojo
用作drools 的fact
package com.us.drink;
/**
* Created by yangyibo on 16/12/13.
*
* 饮酒客户
*/
public class Customer {
private String name;
private int money;
private int drinkSum;
private int blankCup;
private int cap;
public Customer(String name, int money) {
super();
this.name = name;
this.money = money;
this.drinkSum = 0;
this.blankCup = 0;
this.cap = 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public int getDrinkSum() {
return drinkSum;
}
public void setDrinkSum(int drinkSum) {
this.drinkSum = drinkSum;
}
public int getBlankCup() {
return blankCup;
}
public void setBlankCup(int blankCup) {
this.blankCup = blankCup;
}
public int getCap() {
return cap;
}
public void setCap(int cap) {
this.cap = cap;
}
@Override
public String toString() {
return this.name+"同学还有"
+this.money+"元钱,喝了"+this.drinkSum+"瓶酒, 有"
+this.getBlankCup()+"个空瓶和"
+this.getCap()+"个盖子";
}
}
3.2 rules 规则文件
drinkRules.drl 文件
package com.us.drink;
import com.us.drink.Customer;
rule "buy a beer and drink"
salience 1
when
$c: Customer(money >= 2,$m:money,$b:blankCup,$d:drinkSum,$a:cap);
then
$c.setMoney($m-2);
$c.setBlankCup($b+1);
$c.setDrinkSum($d+1);
$c.setCap($a+1);
System.out.println($c.toString());
update($c);
end
rule "sale blank cup get a beer"
salience 3
when
$c : Customer(blankCup>=2,$b:blankCup,$d:drinkSum,$a:cap);
then
$c.setBlankCup($b-1);
$c.setDrinkSum($d+1);
$c.setCap($a+1);
System.out.println($c.toString());
update($c);
end
rule "sale cap and get a beer"
salience 2
when
$c : Customer(cap>=4,$b:blankCup,$d:drinkSum,$a:cap);
then
$c.setCap($a-3);
$c.setBlankCup($b+1);
$c.setDrinkSum($d+1);
System.out.println($c.toString());
update($c);
end
rule "finish drink"
dialect "java"
when
$c:Customer(blankCup < 2,money < 2,cap< 4);
then
System.out.println("finish drink"+$c.toString());
end
3.3 kmodule.xml
如果没有 kmodule.xml 文件,在META-INF 文件夹下新建kmodule.xml 文件填写如下内容
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<!--喝啤酒-->
<kbase name="DrinkBeerKB" packages="com.us.drink">
<ksession name="DrinkBeerKS"/>
</kbase>
</kmodule>
3.4 drinkTest
package com.us.drink;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
/**
* Created by yangyibo on 16/12/13.
*/
public class DrinkBeer {
private static KieSession getSession() {
KieServices ks = KieServices.Factory.get();
KieContainer kc = ks.getKieClasspathContainer();
return kc.newKieSession("DrinkBeerKS");
}
private static void drink() {
KieSession ks = getSession();
Customer c1 = new Customer("奥巴马", 10);
ks.insert(c1);
int count = ks.fireAllRules();
System.out.println("总执行了" + count + "条规则");
System.out.println(c1.toString());
}
public static void main(String[] args) {
drink();
}
}
结语:通过drools 实现,规则信息,清晰易读。且规则灵活可随意修改,做到了规则和数据分离。提高了代码的可读性和可维护性。