先说一下我们的场景:
假如我们现在要给网站举办活动(奖励额外积分), 活动规则如下:
规则如下: 订单原价金额在
100以下, 不加分
100-500 加100分
500-1000 加500分
1000 以上 加1000分
我们可能这样编码:
package com.league.drools.pojo; import java.util.Date; public class Order { private Date bookingDate;//下单日期 private int amout;//订单原价金额 private User user;//下单人 private int score; public int getScore() { return score; } public void setScore(int score) { this.score = score; } public Date getBookingDate() { return bookingDate; } public void setBookingDate(Date bookingDate) { this.bookingDate = bookingDate; } public int getAmout() { return amout; } public void setAmout(int amout) { this.amout = amout; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
package com.league.drools.pojo; public class User { private String name;//姓名 private int level;//用户级别 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } }
package com.league.drools.demo1; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import com.league.drools.pojo.Order; import com.league.drools.pojo.User; public class App { public static void main(String[] args) throws Exception { List<Order> orderList = getInitData(); for (int i=0; i<orderList.size(); i++){ Order order = orderList.get(i); if (order.getAmout() <= 100){ order.setScore(0); addScore(order); }else if(order.getAmout() > 100 && order.getAmout() <= 500){ order.setScore(100); addScore(order); }else if(order.getAmout() > 500 && order.getAmout() <= 1000){ order.setScore(500); addScore(order); }else{ order.setScore(1000); addScore(order); } } } private static void addScore(Order o){ System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore()); } private static List<Order> getInitData() throws Exception { List<Order> orderList = new ArrayList<Order>(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); { Order order = new Order(); order.setAmout(80); order.setBookingDate(df.parse("2015-07-01")); User user = new User(); user.setLevel(1); user.setName("Name1"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(200); order.setBookingDate(df.parse("2015-07-02")); User user = new User(); user.setLevel(2); user.setName("Name2"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(800); order.setBookingDate(df.parse("2015-07-03")); User user = new User(); user.setLevel(3); user.setName("Name3"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(1500); order.setBookingDate(df.parse("2015-07-04")); User user = new User(); user.setLevel(4); user.setName("Name4"); order.setUser(user); orderList.add(order); } return orderList; } }
运行结果:
用户Name1享受额外增加积分: 0 用户Name2享受额外增加积分: 100 用户Name3享受额外增加积分: 500 用户Name4享受额外增加积分: 1000
那么当
用户需求变更时, 比如只有用户等级为2以上的会员才能享受此活动资格.
那么此时必须更改以前的代码, 在if前加上会员级别的判断,然后开发, 测试, 生产部署,走发布版本的流程.
而商家经常搞活动, 那么我们的产品就不得不经常因为这种规则变更而发布新的版本来支持当前的业务.
此时, 我们就可以使用规则引擎(Drools)来解决此类问题.
Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件,数据等介质中,使得规则的变更不需要修正代码甚至不需要重启机器就可以立即在线上环境生效。
OK, 直接上相关代码.
package com.league.drools.demo1; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseConfiguration; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderErrors; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.definition.KnowledgePackage; import org.drools.io.ResourceFactory; import org.drools.runtime.StatefulKnowledgeSession; import com.league.drools.pojo.Order; import com.league.drools.pojo.User; public class App1 { /** * 计算额外积分金额 规则如下: 订单原价金额 * 100以下, 不加分 * 100-500 加100分 * 500-1000 加500分 * 1000 以上 加1000分 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder(); builder.add(ResourceFactory.newClassPathResource("rules/point-rules.drl"), ResourceType.DRL); if (builder.hasErrors()) { System.out.println("规则中存在错误,错误消息如下:"); KnowledgeBuilderErrors kbuidlerErrors = builder.getErrors(); for (Iterator iter = kbuidlerErrors.iterator(); iter.hasNext();) { System.out.println(iter.next()); } return; } Collection<KnowledgePackage> packages = builder.getKnowledgePackages(); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(packages); StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession(); List<Order> orderList = getInitData(); for (int i = 0; i < orderList.size(); i++) { Order o = orderList.get(i); session.insert(o); session.fireAllRules(); // 执行完规则后, 执行相关的逻辑 addScore(o); } session.dispose(); } private static void addScore(Order o){ System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore()); } private static List<Order> getInitData() throws Exception { List<Order> orderList = new ArrayList<Order>(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); { Order order = new Order(); order.setAmout(80); order.setBookingDate(df.parse("2015-07-01")); User user = new User(); user.setLevel(1); user.setName("Name1"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(200); order.setBookingDate(df.parse("2015-07-02")); User user = new User(); user.setLevel(2); user.setName("Name2"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(800); order.setBookingDate(df.parse("2015-07-03")); User user = new User(); user.setLevel(3); user.setName("Name3"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(1500); order.setBookingDate(df.parse("2015-07-04")); User user = new User(); user.setLevel(4); user.setName("Name4"); order.setUser(user); orderList.add(order); } return orderList; } }
package rules import com.league.drools.pojo.Order import com.league.drools.pojo.User rule "zero" no-loop true lock-on-active true salience 1 when $s : Order(amout <= 100) then $s.setScore(0); update($s); end rule "add100" no-loop true lock-on-active true salience 1 when $s : Order(amout > 100 && amout <= 500) then $s.setScore(100); update($s); end rule "add500" no-loop true lock-on-active true salience 1 when $s : Order(amout > 500 && amout <= 1000) then $s.setScore(500); update($s); end rule "add1000" no-loop true lock-on-active true salience 1 when $s : Order(amout > 1000) then $s.setScore(1000); update($s); end
运行结果如下:
用户Name1享受额外增加积分: 0 用户Name2享受额外增加积分: 100 用户Name3享受额外增加积分: 500 用户Name4享受额外增加积分: 1000
如果更改活动规则, 只需要更改drl文件. 重启应用即可.
附MAVEN依赖如下:
<dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>5.6.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>5.6.0.Final</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.9</version> </dependency>