几种规则策略
Posted mr-yang-localhost
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了几种规则策略相关的知识,希望对你有一定的参考价值。
规则的起因
软件开发中经常会有很多复杂的条件判断,满足不同条件的时候执行不同的操作,而这些规则可能并不是一直不变的。
以某市几条积分规则为例:
年龄(最高30分)
* 56-60岁 积5分
* 每减少1岁 加2分
教育背景(最高110分)
* 1:大专(高职); 50分
* 2:本科; 60分
* 3:本科+学历; 90分
* 4:硕士; 100分
* 5:博士 110分
技能类国家职业资格等级(最高140分)
* 1:一级或高级职称; 140分
* 2:二级或中级职称; 100分
* 3:三级; 60分
* 4:四级; 30分
* 5:五级 15分
社保缴纳年限
* year * 3
基于method/bean的简易规则
规则配置:
public class ScoreRule { /** * 规则id */ private Integer ruleId; /** * 规则名 */ private String ruleName; /** * 规则执行者 */ private String ruleExecuter; /** * 规则表达式(可以提供后台修改配置) * eg:{"maxScore":30,"minRegion":56,"maxRegion":60,"regionScore":5,"scorePeYear":2} */ private String ruleExpression; /** * 规则执行顺序 */ private Integer sort; /** * 是否可用 */ private Boolean enable; }
规则执行:
/** * 评估积分 */ public Integer getUserSettleRules(UserInfoDto dto) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Integer baseScore = 0; List<ScoreRule> scoreRuleList = getScoreRuleList().stream().filter(r -> r.getEnable().equals(Boolean.TRUE)).sorted((x, y) -> x.getSort().compareTo(y.getSort())).collect(Collectors.toList()); for (ScoreRule scoreRule : scoreRuleList) { Method method = this.getClass().getDeclaredMethod(scoreRule.getRuleExecuter(), UserInfoDto.class); Integer result = (Integer) method.invoke(this, dto); if (result > 0) { log.info("methodName:" + scoreRule.getRuleExecuter() + ",result:" + result); baseScore += result; } } return baseScore; }
实现简单,将易于变化的参数提供给业务方配置;新增或修改规则需要调整代码重新发布。
类似基于method的方式,将不同的规则实现到不同的bean里,利用 SpringContextUtil.getBean(sortRule.getRuleExecuter()) 获取实现规则的bean,执行对应的规则。
基于qlexpress规则
引用依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.2.0</version>
</dependency>
调用的java的方法:
- userService.getUserInfo(userId);//指定userId获取用户信息
- settleScore.getBaseScoreByEdu(userInfo);//传入userInfo按年龄计算基础积分
- settleScore.getBaseScoreByEdu(userInfo);//传入userInfo按学历计算基础积分
传入参数:
context.put("userId", 2);//给userService.getUserInfo(userId)传入参数
context.put("userService", SpringContextUtil.getBean("userService"));//注入userService。调用userService.getUserInfo(userId)方法
context.put("settleScore", SpringContextUtil.getBean("settleScore"));//注入settleScore。调用settleScore.getBaseScoreByEdu(userInfo)、settleScore.getBaseScoreByEdu(userInfo)方法
UserService获取用户信息示例:
@Service("userService") public class UserService { public UserInfoDto getUserInfo(Integer userId) { if (userId == 1) { UserInfoDto userInfoDto = new UserInfoDto(); userInfoDto.setUserName("张三"); userInfoDto.setAge(35); userInfoDto.setDegreeOfEdu(1); userInfoDto.setSkillLevel(1); userInfoDto.setSocialSecurity(1); return userInfoDto; } UserInfoDto userInfoDto = new UserInfoDto(); userInfoDto.setUserName("张三"); userInfoDto.setAge(58); userInfoDto.setDegreeOfEdu(1); userInfoDto.setSkillLevel(1); userInfoDto.setSocialSecurity(1); return userInfoDto; } }
规则完整示例:
public void testQlExpress() throws Exception { String qlExpress = "score = 0;" + "userInfo = userService.getUserInfo(userId); " + "if(userInfo.age > 0 && userInfo.age <= 60) { " + "result = settleScore.getBaseScoreByAge(userInfo); " + "System.out.println(‘>>>cal age score..........result:‘+result);" + "score = score + result;" + "} if(userInfo.degreeOfEdu >= 1 && userInfo.degreeOfEdu <= 5) { " + "result = settleScore.getBaseScoreByEdu(userInfo); " + "System.out.println(‘>>>cal edu score..........result:‘+result);" + "score = score + result;" + "} " + "System.out.println(‘return result:‘+result);" + "return score;"; ExpressRunner runner = new ExpressRunner(); DefaultContext<String, Object> context = new DefaultContext<>(); context.put("userId", 2); context.put("userService", SpringContextUtil.getBean("userService")); context.put("settleScore", SpringContextUtil.getBean("settleScore")); Object result = runner.execute(qlExpress, context, null, true, false); System.out.println("score result:" + result); }
执行结果:
2018-06-25 13:38:07.634 [INFO][http-nio-8088-exec-1]:c.demo.scorerule.SettleScore [getBaseScoreByAge:73] 基础积分计算>>>年龄积分:5
>>>cal age score..........result:5
2018-06-25 13:38:07.639 [INFO][http-nio-8088-exec-1]:c.demo.scorerule.SettleScore [getBaseScoreByEdu:121] 基础积分计算>>>教育背景:50
>>>cal edu score..........result:50
return result:50
score result:55
基于drools规则
将规则实现在drl文件里,java读取drl文件执行规则,可以做到动态更新drl规则而不需要发布。
引用drools包(drools5.5与java8不兼容问题参考):
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>5.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>5.5.0.Final</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
</exclusion>
</exclusions>
</dependency>
drl规则实现:
package com.drools.demo.point import com.logback.demo.scorerule.UserInfoDto; import com.logback.demo.scorerule.UserBaseScore; rule "ageBaseScore" // salience 2 lock-on-active true when $userInfo : UserInfoDto(age >= 56 && age <= 60); then UserBaseScore.addScore(5); System.out.println("age between 56 and 60"); $userInfo.recordPointLog($userInfo.getUserName(),"ageBaseScore"); end rule "ageCalScore" // salience 3//优先级,值越大越先执行 lock-on-active true when $userInfo : UserInfoDto(age < 56); then System.out.println("age less than 56. age:"+$userInfo.getAge()); Integer ageScore = (56 - $userInfo.getAge()) * 2; UserBaseScore.addScore(ageScore > 30 ? 30 : ageScore); $userInfo.recordPointLog($userInfo.getUserName(),"ageCalScore"); end rule "eduLevel1Score" // salience 3//优先级,值越大越先执行 lock-on-active true when $userInfo : UserInfoDto(degreeOfEdu == 1); then System.out.println("edu level is:"+$userInfo.getDegreeOfEdu()); UserBaseScore.addScore(50); $userInfo.recordPointLog($userInfo.getUserName(),"eduLevel1Score"); end
以上是关于几种规则策略的主要内容,如果未能解决你的问题,请参考以下文章
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)