今天放福利幹貨, 由于接觸到了遇到了很多關于比對條件判斷的業務場景和需求,很多人可能不假思索的就直接幹if-else,可能對代碼有點追求的上了層次幹政策模式,噼噼啪啪絞盡腦汁設計了一啪優雅牛逼的代碼接口和實作,其實做過風控系統的同學們應該對規則引擎都不陌生,可以執行百度,規則引擎有好多,傳統的我曾經用過的和感覺最容易上手的當屬drools了,今天就幹他,分享一下
直接開幹
普通規則寫法
先來常常鮮,堆疊式的規則寫法,将所有的判斷條件全部寫一個規則,重複累贅
package rules;
import com.example.drools.Fd.domain.TradeRecord
import java.math.BigDecimal
import org.slf4j.LoggerFactory
global org.slf4j.Logger logger
rule "Between3And12"
when
trd:TradeRecord(getFqNum() >=3 && getFqNum() < 12)
then
trd.setFee(new BigDecimal("0.05").multiply(trd.getAmount()));
logger = LoggerFactory.getLogger("Drools-Between3And12");
logger.info("命中費率規則 :12期以上24期以内");
end
rule "Between12And24"
when
trd:TradeRecord(getFqNum() >= 12 && getFqNum() < 24)
then
trd.setFee(new BigDecimal("0.25").multiply(trd.getAmount()));
logger = LoggerFactory.getLogger("Drools-Between12And24");
logger.info("命中費率規則 :12期以上24期以内");
end
今天來個進階的,首先編寫一段規則模闆,對我又在用模闆方式
模闆腳本:
這是一個根據交易分期數來比對對應的期數費率區間,其實延伸開來,例如價格區間優化折扣、等這種帶區間的需求都可以這樣去實作,動态,易于維護,邏輯簡單清晰易懂
package rules;
dialect "java"
import java.math.BigDecimal
import com.example.drools.Fd.domain.TradeRecord
import org.slf4j.LoggerFactory
global com.example.drools.Fd.domain.Fenqi fqs
global org.slf4j.Logger logger
rule "BetweenMinAndMax"
when
trd:TradeRecord(getFqNum() >= fqs.getMin() && getFqNum() < fqs.getMax())
then
trd.setFee(new BigDecimal(fqs.getRadio()).multiply(trd.getAmount()));
logger = LoggerFactory.getLogger("Drools-BetweenMinAndMax");
logger.info("命中費率規則 : {} 期以上(包含),{} 期以内",fqs.getMin(),fqs.getMax());
end
規則擷取參數
- 可以使用global關鍵字将java參數定義成一個全局變量參數,在整個規則中都能使用到
- 使用 session.setGlobal("fqs",fenqishu) 傳遞全局參數
- 傳參,使用session.insert(tradeRecord),規則中就像java代碼一樣絲滑
java執行代碼:
簡單模拟
- 一筆交易事實,100元的交易分了6期
- 3期到12期之間執行的費率是0.25%
- 命中規則,并之間計算分期費用,規則結果傳回費用結果
public void getOutRuleFiles() throws IOException {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
File[] ruleFiles = Paths.get("d://temp/rules//").toFile().listFiles();
for (File file : ruleFiles) {
kieFileSystem.write(ResourceFactory.newFileResource(file));
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
KieContainer kContainer = kieServices.newKieContainer(kieBuilder.getKieModule().getReleaseId());
KieBase kieBase = kContainer.getKieBase();
KieSession session = kieBase.newKieSession();
//交易事實
TradeRecord tradeRecord = new TradeRecord();
tradeRecord.setAmount(new BigDecimal(100));
tradeRecord.setFqNum(6);
tradeRecord.setMerchantName("删古");
session.insert(tradeRecord);
//條件事實
Fenqi fenqishu = new Fenqi();
fenqishu.setMax(12);
fenqishu.setMin(3);
fenqishu.setRadio(0.25);
session.setGlobal("fqs",fenqishu);
session.fireAllRules();
session.dispose();
System.out.println("命中規則計費結果:"+tradeRecord.getFee());
}
工程結構:spring-boot
pom依賴
總結
其實drools不是什麼新技術,很老的東西了,但是網上很多用法是直接将規則寫到工程本身的/main/resources/目錄下,試想一下,如果這樣就不太友善了,如果規則随時需要變動,那不是要重新打包嗎,是以結合實踐,把規則拿出來放在指定外部目錄中是非常有必要的,就幾行代碼就能解決多少if判斷,将規則做成API,也能實作解耦,技術不複雜,思路和解決方案更重要,希望對路過的朋友有所幫助。