Drools一個很好的例子
轉自http://www.360doc.com/content/15/0701/15/5054188_481943680.shtml
一、問題描述
假設僱員 Employ 有:
學歷資訊 eduInfo , 簡歷資訊 resume ,
考核資訊 annualExam 和獎懲資訊 awardPunish ;
要確定其:
基本工資 basicSalary ,職務工資 dutySalary ,
分紅金額 bonus 和 總工資 totalSalary .
規則如下:
【 1 】學歷決定基本工資( basicSalary ):
====> 本科 1500 研究生 2500
【 2 】簡歷決定職務工資 (dutySalary) :
====> 技術 2000 管理 4500
【 3 】年度考核決定分紅 (bonus) :
====> 分紅總金額 1000
==> 考核結果:
==> 優秀 100% ( 1000 );良好 90% ( 900 );
合格 60% ( 600 ); 不合格 0% ( 0 );
【 4 】獎懲決定計算最終工資與【 123 】項工資之和的比例:
====> 獎勵: * 110% ( +10% )
====> 懲罰: * 90% ( -10% )
====> 無: * 100% ( 0% )
【 5 】計算總工資: (【 1 】 + 【 2 】 + 【 3 】) * 【 4 】
二、問題分析
1. 基本流程:
P 【計算基本工資,計算職務工資,計算分紅, 計算獎懲比例】
====> 計算總工資 ( 根據獎懲情況 )
其中, P[i,...,k] 表示任務 i,...,k 併發執行, ====> 表示順序執行。
即有: P[1,2,3, 4] ===> 5
三、概要設計
【 1 】類 Employ 的設計:
【 2 】規則檔案的編寫和組織:
==> 學歷規則檔案: EduInfoRule.drl
==> 簡歷規則檔案: ResumeRule.drl
==> 分紅規則檔案: BonusRule.drl
==> 獎懲規則檔案: AwardPunish.drl
==> 計算總工資規則: TotalRule.drl
【 3 】規則檔案的組合(規則流):
==> EduInfo.drl 含規則組 basic_salary
==> ResumeRule.drl 含規則組 duty_salary
==> BonusRule.drl 含規則組 bonus_salary
==> AwardPunish.drl 含規則組 award_punish
==> TotalRule.drl 含規則組 sum_salary
組合方式:
[start] ---> P[ basic_sal ary , duty_salary, bonus_salary, award_punish ]
---> sum_salary ---> [end]
其中: P 表示併發, ---> 表示順序 【規則流圖在後面的實現中給出】
【 4 】編寫測試檔案: EmployTest.java
四、詳細設計
【 1 】使用 Eclipse IDE 作為開發環境, drools5.1 作為規則引擎
【 2 】 為簡單起見, Employ 類的屬性作了簡化處理,
eduInfo , resume , annualExam, awardPunish 均為 String ,
basic{duty,bonus, total}_salary , percent 作為 double 型別。
五、規則檔案及規則流
EduInfoRule.drl :
package myrules;
import sample.Employ;
rule "Bachelor"
ruleflow-group "basic_salary"
when
emp: Employ(eduInfo == "bachelor" );
then
System.out.println( "exec rule Bachelor ... " );
emp.setBasicSalary(1500);
end
rule "Master"
ruleflow-group "basic_salary"
when
emp: Employ(eduInfo== "master" )
then
System.out.println( "exec rule Master ... " );
emp.setBasicSalary(2500);
end
Resume.drl
package myrules
import sample.Employ;
rule "Technician"
ruleflow-group "duty_salary"
when
emp: Employ(resume== "tech" )
then
System.out.println( "exec rule Technician ... " );
emp.setDutySalary(2000);
end
rule "Manager"
ruleflow-group "duty_salary"
when
emp: Employ(awardPunish== "manager" )
then
System.out.println( "exec rule manager ... " );
emp.setDutySalary(4500);
end
BonusRule.drl
package myrules
import sample.Employ;
rule "Excellent"
ruleflow-group "bonus_salary"
when
emp: Employ(annualExam== "excellent" )
then
System.out.println( "exec rule Excellent ... " );
emp.setBonus(1000*1.0);
end
rule "Good"
ruleflow-group "bonus_salary"
when
emp: Employ(annualExam== "good" )
then
System.out.println( "exec rule Good ... " );
emp.setBonus(1000*0.9);
end
rule "Common"
ruleflow-group "bonus_salary"
when
emp: Employ(annualExam== "common" )
then
System.out.println( "exec rule Common ... " );
emp.setBonus(1000*0.6);
end
rule "failing"
ruleflow-group "bonus_salary"
when
emp: Employ(annualExam== "failing" )
then
System.out.println( "exec rule failing ... " );
emp.setBonus(1000*0.0);
end
AwardPunish.drl
package myrules
import sample.Employ;
rule "Award"
ruleflow-group "award_punish"
when
emp: Employ(awardPunish== "award" )
then
System.out.println( "exec rule Award ... " );
emp.setPercent(1.10);
end
rule "Punishment"
ruleflow-group "award_punish"
when
emp: Employ(awardPunish== "punish" )
then
System.out.println( "exec rule Punishment ... " );
emp.setPercent(0.90);
end
rule "None"
ruleflow-group "award_punish"
when
emp: Employ(awardPunish== "none" )
then
System.out.println( "exec rule None ... " );
emp.setPercent(1.00);
end
TotalRule.drl
package myrules
import sample.Employ;
rule "Total"
ruleflow-group "sum_salary"
when
emp: Employ()
then
System.out.println( "exec rule Total ... " );
double total = emp.getBasicSalary() + emp.getDutySalary() +
emp.getBonus();
emp.setTotalSalary(total*emp.getPercent());
end
建立規則流檔案 simple.rf :
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
注意:
[1] Split 結點型別為 OR ,約束選擇 always true. 表示選擇其規則組中所有符合事實的規則進行併發執行;
[2] Join 結點型別為 AND ,表示當且進當上述規則組均執行完畢後,才執行後面的規則或程序。
六、測試程式碼:
Employ:
package sample;
public class Employ {
public static final double BONUS = 1000;
private String eduInfo ;
private String resume ;
private String annualExam ;
private String awardPunish ;
private double basicSalary ;
private double dutySalary ;
private double bonus ;
private double percent ;
private double totalSalary ;
// getter/setter methods
public String toString() {
return "[" + eduInfo + " " + resume + " " + annualExam +
" " + awardPunish + " " + basicSalary + " " + dutySalary +
" " + bonus + " " + totalSalary + "]" ;
}
}
EmployTest:
package sample;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
public class EmployTest {
public static void main(String[] args) {
try {
// load up the knowledge base
KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
// go !
Employ emp = new Employ();
emp.setEduInfo("master");
emp.setResume("tech");
emp.setAnnualExam("good");
emp.setAwardPunish("award");
ksession.insert(emp);
ksession.startProcess("myrules.salary");
ksession.fireAllRules();
System.out.println("Basic Salary: " + emp.getBasicSalary());
System.out.println("Duty Salary: " + emp.getDutySalary());
System.out.println("Bonus : " + emp.getBonus());
System.out.println("rate : " + emp.getPercent());
System.out.printf("Total Salary: %.0f" , emp.getTotalSalary());
logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("EduInfoRule.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("ResumeRule.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("BonusRule.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("AwardPunish.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("TotalRule.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("salary.rf"), ResourceType.DRF);
KnowledgeBuilderErrors errors = kbuilder.getErrors();
if (errors.size() > 0) {
for (KnowledgeBuilderError error: errors) {
System.err.println(error);
}
throw new IllegalArgumentException("Could not parse knowledge.");
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
return kbase;
}
}
測試結果:
exec rule Technician ...
exec rule Master ...
exec rule Good ...
exec rule Award ...
exec rule Total ...
Basic Salary: 2500.0
Duty Salary: 2000.0
Bonus : 900.0
rate : 1.1
Total Salary: 5940
七、總結
Java drools 規則流基礎:
【 1 】掌握規則引擎的基本工作原理;
【 2 】掌握規則檔案的編寫;
【 3 】掌握規則流圖的繪製及應用程式整合。
【 4 】掌握規則組合的兩種基本方式【併發和順序】的實現方式。
下一步:
【 1 】更復雜的規則組合;
【 2 】規則檔案的組織、管理;
【 3 】規則檔案的自動生成;
【 4 】使用者自定義規則;