本文用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 实现,规则信息,清晰易读。且规则灵活可随意修改,做到了规则和数据分离。提高了代码的可读性和可维护性。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/15223.html