本文给出了如何利用Drools来执行业务规则实例。
考虑这样一种情况,某 学校USST希望招收的学校其年龄应该大于15岁,另外一个学校FUDAN希望其招收的学生大于18岁.当然,不同的学校对学生的要求可能不一样,例如年 龄、性别、成绩等。如果采用大量的if...else语句写在业务逻辑层,将来随着学校招生的要求变化,需要应用程序开发人员,不断的修改业务规则。现在 考虑采用Drools来使商务逻辑从应用程序中分离出来。
1。首先设计一个Student类,包括姓名、年龄、性别、希望就读学校。类文件如下:
package com.primeton.juxtapose.rule.example;
/**
* 简单的JavaBean保存student值。用于存放与学生相关的信息。
* 包括 姓名、年龄、性别、是否推荐入学等。
*
* 根据学生的性别、年龄等判断该学生是否可以入读某一学校。
* 如: 某女子学校可能只接受性别为女的学生;
* 某学校可能只接受年龄大于15岁的学生入学;
* 某女子学校可能只接受性别为女且年龄大于18岁的学生入学;
* ......
*
* @author liuxiang
*
*/
public class Student {
//常量
public final static String YES="YES";
public final static String NO="NO";
//内部变量
private String studentName =null;
private int studentAge = 0;
private String studentSex = null;
private String recommend = null;
private String schoole = null;
/**
* 设置学生姓名
* @param studentName
*/
public void setStudentName(String studentName){
this.studentName = studentName;
}
/**
* 获得学生姓名
* @return
*/
public String getStudentName(){
return this.studentName;
}
/**
* 设置学生年龄
* @param studentAge
*/
public void setStudentAge(int studentAge){
this.studentAge = studentAge;
}
/**
* 获得学生年龄
* @return
*/
public int getStudentAge(){
return this.studentAge;
}
/**
* 设置学生性别
* @param studentSex
*/
public void setStudentSex(String studentSex){
this.studentSex = studentSex;
}
/**
* 获得学生性别
* @return
*/
public String getStudentSex(){
return this.studentSex;
}
/**
* 设置是否推荐入学
* @param recommend
*/
public void setRecommend(String recommend){
this.recommend = recommend;
}
/**
* 获得是否推荐入学
* @return
*/
public String getRecommend(){
return this.recommend;
}
/**
* 设置孩子希望就读的学校
* @param schoole
*/
public void setSchoole(String schoole){
this.schoole = schoole;
}
/**
* 获得孩子希望就读的学校
* @return
*/
public String getSchoole(){
return this.schoole;
}
}
2。对于业务逻辑考虑用一个简单得Java类来实现,用来模拟执行商业逻辑。类BusinessLogicLayer,用于模拟商业逻辑的执行。
package com.primeton.juxtapose.rule.example;
import java.io.IOException;
import org.drools.DroolsException;
import org.drools.IntegrationException;
import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.event.DebugWorkingMemoryEventListener;
import org.drools.io.RuleBaseLoader;
import org.drools.spi.Activation;
import org.drools.spi.AgendaFilter;
import org.xml.sax.SAXException;
/**
* 一个简单的业务逻辑层,用来模拟商业逻辑。
*
* @author liuxiang
*
*/
public class BusinessLogicLayer {
private static final String BUSINESS_RULE_FILE="BusinessRulesStudent.drl";
private static RuleBase businessRules = null;
// 设置过滤条件, 名称为"FemaleSchoole"的规则将不会被执行。
private static AgendaFilter filter = new AgendaFilter(){
public boolean accept(Activation activation){
if (activation.getRule().getName().equals("Stude")){
return false;
}
return true;
}
};
/**
* 如果还没有装载商务规则的话就装载它。
* @throws IOException
* @throws SAXException
* @throws IntegrationException
*@抛出异常 -通常从这里恢复
*/
private static void loadRules() throws IntegrationException, SAXException, IOException {
if (businessRules==null){
businessRules = RuleBaseLoader.loadFromUrl(com.primeton.juxtapose.rule.example.BusinessLogicLayer.class.getResource(BUSINESS_RULE_FILE ) );
}
}
/**
* 评价学生是否能够入学
* @param stockToBuy
* @throws Exception
*/
public static void evaluateStudentRecommend(Student student) throws Exception{
loadRules();
System.out.println( "FIRE All RULES" );
System.out.println( "------------------------------------------------------------" );
WorkingMemory workingMemory = businessRules.newWorkingMemory();
workingMemory.addEventListener(new DebugWorkingMemoryEventListener());
workingMemory.assertObject(student);
workingMemory.fireAllRules(filter);
}
/**
* 测试用例
* 测试学生juxtapose就读USST学校 是否符合条件
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
//BusinessLayer businessLayer = new BusinessLayer();
Student student = new Student();
student.setSchoole("USST");
student.setStudentName("juxtapose");
student.setStudentAge(20);
student.setStudentSex("Male");
BusinessLogicLayer.evaluateStudentRecommend(student);
}
}
3。 在该类的运行时需要用到规则的定义,采用XML的方式来描述商务逻辑中用到的各种规则。规则文件BusinessRulesStudent.drl的定义如下:
<rule-set name="BusinessRulesSample"></rule-set>xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd">
<java:import>java.lang.Object </java:import>
<java:import>java.lang.String </java:import>
<java:import>com.primeton.juxtapose.rule.example.Student </java:import>
<java:functions>
public static void printStudent(com.primeton.juxtapose.rule.example.Student student){
System.out.println(" Student Name:"+student.getStudentName()
+"n Sudent Age: "+student.getStudentAge()
+"n Student Sex:"+student.getStudentSex()
+"n Recommend "+student.getStudentName()
+" to go to schoole "
+student.getSchoole()
+": "
+student.getRecommend());
}
</java:functions>
<rule name="USSTSchoole" salience="-1"></rule>
<parameter identifier="student"></parameter>
<class></class>com.primeton.juxtapose.rule.example.Student
<java:condition>student.getSchoole().equals("USST") </java:condition>
<java:condition>student.getStudentAge() > 15 </java:condition>
<java:consequence>
student.setRecommend(Student.YES);
printStudent(student);
</java:consequence>
<rule name="FUDANSchoole" salience="-1"></rule>
<parameter identifier="student"></parameter>
<class></class>com.primeton.juxtapose.rule.example.Student
<java:condition>student.getSchoole().equals("FUDAN") </java:condition>
<java:condition>student.getStudentAge() > 18 </java:condition>
<java:consequence>
student.setRecommend(Student.YES);
printStudent(student);
</java:consequence>
在该规则文件中共设置了两个规则,其规则名分别为USSTSchoole、FUDANSchoole,前者用于执行就读USST学校的规则设置,其条件为:
就读学校为 USST,学生年龄大于15岁,推荐就读变量为null; 后者FUDANSchoole规则用于执行就读FUDAN学校的规则设置,其条件为:
就读学校为 FUDAN,学生年龄大于8岁,推荐就读变量为null;
4。利用Junit进行测试。测试类BusinessLogicLayerTest.java包含两个测试方法,分别用于执行就读USST和FUDAN学校的测试。
package com.primeton.juxtapose.rule.example;
import junit.framework.TestCase;
/**
* 商务逻辑的单元测试,
* 用于检测我们的业务规则是否得到了正确的执行。
*
* @author liuxiang
*
*/
public class BusinessLogicLayerTest extends TestCase {
/**
* 测试学生juxtapose就读USST学校 是否符合条件
* @throws Exception
*/
public void testGotoUSST() throws Exception{
//创建一个学生实例,目标就读学校为USST
Student student = new Student();
student.setSchoole("USST");
student.setStudentName("juxtapose");
student.setStudentAge(16);
student.setStudentSex("Male");
//运行规则
BusinessLogicLayer.evaluateStudentRecommend(student);
//测试该学生能够入学 符合规则中设定的条件
//assertTrue(student.getRecommend() != null);
assertTrue("YES".equals(student.getRecommend()));
}
public void testGotoFUDAN() throws Exception{
//创建一个学生实例,目标就读学校为USST
Student student = new Student();
student.setSchoole("FUDAN");
student.setStudentName("jxta");
student.setStudentAge(20);
student.setStudentSex("Male");
//运行规则
BusinessLogicLayer.evaluateStudentRecommend(student);
//测试该学生能够入学 符合规则中设定的条件
//assertTrue(student.getRecommend() != null);
assertTrue("YES".equals(student.getRecommend()));
}
}
5。执行结果。
FIRE All RULES
------------------------------------------------------------ Student Name:juxtapose
Sudent Age: 16
Student Sex:Male
Recommend juxtapose to go to schoole USST: YES
FIRE All RULES
------------------------------------------------------------
Student Name:jxta
Sudent Age: 20
Student Sex:Male
Recommend jxta to go to schoole FUDAN: YES
6。结论
利用Drools可以轻松的在系统上线后,通过执行规则的替换、增加、修改。使得商务逻辑从应用程序中分离出来,大幅度的提高了系统的柔韧性、适应性,满足了日益变化的市场需求。