zoukankan      html  css  js  c++  java
  • 几种规则策略

    规则的起因

    软件开发中经常会有很多复杂的条件判断,满足不同条件的时候执行不同的操作,而这些规则可能并不是一直不变的。

    以某市几条积分规则为例:

    年龄(最高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
  • 相关阅读:
    作品第二课----改变DIV任意属性的值
    今天遇到的mouseout和mouseleave之坑
    作品第二课----弹出层
    作品第二课----求数组中所有数字的和
    作品第二课----点击DIV显示其内容
    作品第二课----点击切换显示隐藏
    Linux 静态库与动态库
    Linux学习6-套接字
    Linux学习5-线程
    Linux学习4-信号
  • 原文地址:https://www.cnblogs.com/mr-yang-localhost/p/9204208.html
Copyright © 2011-2022 走看看