Java多条件判断场景中规则执行器的设计

业务场景

近日在公司领到一个小需求,需要对之前已有的试用用户申请规则进行拓展。我们的场景大概如下所示:

if (是否海外用户) {
 return false;
}

if (刷单用户) {
  return false;
}

if (未付费用户 && 不再服务时段) {
  return false
}

if (转介绍用户 || 付费用户 || 内推用户) {
  return true;
}

按照上述的条件我们可以得出的结论是:

  • 咱们的的主要流程主要是基于 and 或者 or 的关系。
  • 如果有一个不匹配的话,其实咱们后续的流程是不用执行的,就是需要具备一个短路的功能。
  • 对于目前的现状来说,我如果在原有的基础上来该,只要稍微注意一下解决需求不是很大的问题,但是说后面可维护性非常差。

后面进过权衡过后,我还是决定将这个部分进行重构一下。

规则执行器

针对这个需求,我首先梳理了一下咱们规则执行器大概的设计, 然后我设计了一个 V1 版本和大家一起分享一下,如果大家也有这样的 case 可以给我分享留言,下面部分主要是设计和实现的流程和 code .

规则执行器的设计

对于规则的抽象并实现规则

// 业务数据
@Data
public class RuleDto {
  private String address;
 private int age;
}

// 规则抽象
public interface BaseRule {

    boolean execute(RuleDto dto);
}

// 规则模板
public abstract class AbstractRule implements BaseRule {

    protected <T> T convert(RuleDto dto) {
        return (T) dto;
    }

    @Override
    public boolean execute(RuleDto dto) {
        return executeRule(convert(dto));
    }

    protected <T> boolean executeRule(T t) {
        return true;
    }
}

// 具体规则- 例子1
public class AddressRule extends AbstractRule {

    @Override
    public boolean execute(RuleDto dto) {
        System.out.println("AddressRule invoke!");
        if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
            return true;
        }
        return false;
    }
}

// 具体规则- 例子2
public class NationalityRule extends AbstractRule {

    @Override
    protected <T> T convert(RuleDto dto) {
        NationalityRuleDto nationalityRuleDto = new NationalityRuleDto();
        if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
            nationalityRuleDto.setNationality(MATCH_NATIONALITY_START);
        }
        return (T) nationalityRuleDto;
    }

    @Override
    protected <T> boolean executeRule(T t) {
        System.out.println("NationalityRule invoke!");
        NationalityRuleDto nationalityRuleDto = (NationalityRuleDto) t;
        if (nationalityRuleDto.getNationality().startsWith(MATCH_NATIONALITY_START)) {
            return true;
        }
        return false;
    }
}

// 常量定义
public class RuleConstant {
    public static final String MATCH_ADDRESS_START= "北京";
    public static final String MATCH_NATIONALITY_START= "中国";
}

执行器构建

public class RuleService {

    private Map<Integer, List<BaseRule>> hashMap = new HashMap<>();
    private static final int AND = 1;
    private static final int OR = 0;

    public static RuleService create() {
        return new RuleService();
    }

    public RuleService and(List<BaseRule> ruleList) {
        hashMap.put(AND, ruleList);
        return this;
    }

    public RuleService or(List<BaseRule> ruleList) {
        hashMap.put(OR, ruleList);
        return this;
    }

    public boolean execute(RuleDto dto) {
        for (Map.Entry<Integer, List<BaseRule>> item : hashMap.entrySet()) {
            List<BaseRule> ruleList = item.getValue();
            switch (item.getKey()) {
                case AND:
                    // 如果是 and 关系,同步执行
                    System.out.println("execute key = " + 1);
                    if (!and(dto, ruleList)) {
                        return false;
                    }
                    break;
                case OR:
                    // 如果是 or 关系,并行执行
                    System.out.println("execute key = " + 0);
                    if (!or(dto, ruleList)) {
                        return false;
                    }
                    break;
                default:
                    break;
            }
        }
        return true;
    }

    private boolean and(RuleDto dto, List<BaseRule> ruleList) {
        for (BaseRule rule : ruleList) {
            boolean execute = rule.execute(dto);
            if (!execute) {
                // and 关系匹配失败一次,返回 false
                return false;
            }
        }
        // and 关系全部匹配成功,返回 true
        return true;
    }

    private boolean or(RuleDto dto, List<BaseRule> ruleList) {
        for (BaseRule rule : ruleList) {
            boolean execute = rule.execute(dto);
            if (execute) {
                // or 关系匹配到一个就返回 true
                return true;
            }
        }
        // or 关系一个都匹配不到就返回 false
        return false;
    }
}

执行器的调用

public class RuleServiceTest {

    @org.junit.Test
    public void execute() {
        //规则执行器
        //优点:比较简单,每个规则可以独立,将规则,数据,执行器拆分出来,调用方比较规整
        //缺点:数据依赖公共传输对象 dto

        //1. 定义规则  init rule
        AgeRule ageRule = new AgeRule();
        NameRule nameRule = new NameRule();
        NationalityRule nationalityRule = new NationalityRule();
        AddressRule addressRule = new AddressRule();
        SubjectRule subjectRule = new SubjectRule();

        //2. 构造需要的数据 create dto
        RuleDto dto = new RuleDto();
        dto.setAge(5);
        dto.setName("张三");
        dto.setAddress("北京");
        dto.setSubject("数学");;

        //3. 通过以链式调用构建和执行 rule execute
        boolean ruleResult = RuleService
                .create()
                .and(Arrays.asList(nationalityRule, nameRule, addressRule))
                .or(Arrays.asList(ageRule, subjectRule))
                .execute(dto);
        System.out.println("this student rule execute result :" + ruleResult);
    }
}

总结

规则执行器的优点和缺点

优点:

比较简单,每个规则可以独立,将规则,数据,执行器拆分出来,调用方比较规整;
我在 Rule 模板类中定义 convert 方法做参数的转换这样可以能够,为特定 rule 需要的场景数据提供拓展。

缺点:上下 rule 有数据依赖性,如果直接修改公共传输对象 dto 这样设计不是很合理,建议提前构建数据。

到此这篇关于Java多条件判断场景中规则执行器的设计的文章就介绍到这了,更多相关Java多条件判断规则执行器 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用JAVA8 filter对List多条件筛选的实现

    记录项目开发的过程中遇到的一些问题及解决方法,由于公司操作数据库都是统一使用工具生成的存在一些多表查询模糊查询,这些操作只能在集合方面下手了,比如发送邮件记录方面查询,对用户的名字及邮件模糊检索 年龄匹配查询. 1.创建实体类: 2.初始化数据 3.对数据进行模糊检索操作 4.多个年龄匹配 模糊检索代码 List<user> filter= users.stream() .filter(user -> user.getName().indexOf("月") >

  • 浅谈java实现mongoDB的多条件查询

    需求:在mongDB客户端,我们很容易实现多条件查询,那么使用java操作时怎么实现呢? 客户端代码: db.url.find({index:4,status:0,url:{$regex:"2016"}}).limit(1) java代码主要用到DBObject BasicDBObject doc5 = new BasicDBObject(); doc5.put("index", 3); doc5.put("status", 0); //doc5

  • java Collections 排序--多条件排序实例

    我就废话不多说了,大家还是直接看代码吧~ // 告警排序 Collections.sort(domesticAirport, comparator); // 告警排序 Comparator<AirportRtWeatherWarningBeanForTable> comparator = new Comparator<AirportRtWeatherWarningBeanForTable>() { @Override public int compare(AirportRtWeat

  • Java多条件判断场景中规则执行器的设计

    业务场景 近日在公司领到一个小需求,需要对之前已有的试用用户申请规则进行拓展.我们的场景大概如下所示: if (是否海外用户) { return false; } if (刷单用户) { return false; } if (未付费用户 && 不再服务时段) { return false } if (转介绍用户 || 付费用户 || 内推用户) { return true; } 按照上述的条件我们可以得出的结论是: 咱们的的主要流程主要是基于 and 或者 or 的关系. 如果有一个不匹

  • mybatis if test条件判断语句中的判断问题分析

    目录 iftest条件判断语句中的判断问题 我在mybatis中定义的sql语句如下 或使用equals() mybatis中iftest判断大坑 使用Mybatis时,常常会判断属性是否为空 原因分析 if test条件判断语句中的判断问题 写这个主要是描述在mybatis中要注意的问题,很不幸,自己没注意,跳坑了. 我在mybatis中定义的sql语句如下 <if test="facilityOccupied != null and facilityOccupied != '' and

  • Linux shell条件判断if中的-a到-z的意思【推荐】

    [ -a FILE ] 如果 FILE 存在则为真. [ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真. [ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真. [ -d FILE ] 如果 FILE 存在且是一个目录则为真. [ -e FILE ] 如果 FILE 存在则为真. [ -f FILE ] 如果 FILE 存在且是一个普通文件则为真. [ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真. [ -h FILE ] 如果 FILE

  • 全面掌握Java中的循环控制语句与条件判断语句的使用

    循环控制 可能存在一种情况,当我们需要执行的代码块数次,通常被称为一个循环. Java有非常灵活的三循环机制.可以使用以下三种循环之一: while 循环 do...while 循环 for 循环 截至Java5,对增强的for循环进行了介绍.这主要是用于数组. while 循环 while循环是一个控制结构,可以重复的特定任务次数. 语法 while循环的语法是: while(Boolean_expression) { //Statements } 在执行时,如果布尔表达式的结果为真,则循环中

  • Spring Boot中的那些条件判断的实现方法

    Spring Boot中的那些Conditional spring boot中为我们提供了丰富的Conditional来让我们得以非常方便的在项目中向容器中添加Bean.本文主要是对各个注解进行解释并辅以代码说明其用途. 所有ConditionalOnXXX的注解都可以放置在class或是method上,如果方式在class上,则会决定该class中所有的@Bean注解方法是否执行. @Conditional 下面其他的Conditional注解均是语法糖,可以通过下面的方法自定义Conditi

  • Java利用策略模式实现条件判断,告别if else

    目录 定义 使用场景 案例 需求 实现方案 方案分析 总结 定义 策略模式定义了一系列算法,并且将每个算法封装起来,使得他们可以相互替换,而且算法的变化不会影响使用算法的客户端. 使用场景 一个系统需要动态的在几种算法中选择一种,可以把每个算法封装到具体的策略类中 一个类中定义了多种行为,可以去代替条件转移语句,减少硬编码 系统中各个算法或者说函数是彼此独立的,而且要求对客户隐藏算法具体实现细节的时候 多个类只区别在表现行为的不同,可以使用策略模式,在运行时动态的选择要执行的行为 案例 需求 根

  • Python中的True,False条件判断实例分析

    本文实例讲述了Python中的True,False条件判断用法.分享给大家供大家参考.具体分析如下: 对于有编程经验的程序员们都知道条件语句的写法: 以C++为例: 复制代码 代码如下: if (condition)  {      doSomething();  } 对于Python中的条件判断语句的写法则是下面的样子: 复制代码 代码如下: if (condition):      doSomething() 那么对于条件语句中的condition什么时候为真什么时候为假呢? 在C++/Ja

  • Nginx中if语句的判断条件与多条件判断详解

    一.if语句中的判断条件(nginx)介绍 1.正则表达式匹配: ==:等值比较; ~:与指定正则表达式模式匹配时返回"真",判断匹配与否时区分字符大小写: ~*:与指定正则表达式模式匹配时返回"真",判断匹配与否时不区分字符大小写: !~:与指定正则表达式模式不匹配时返回"真",判断匹配与否时区分字符大小写: !~*:与指定正则表达式模式不匹配时返回"真",判断匹配与否时不区分字符大小写: 2.文件及目录匹配判断: -f,

  • mybatis中的多重if 条件判断

    目录 mybatis多重if条件判断 要注意的是 mybatis常用判断语法(标签) 1.if判断 2.choose判断 mybatis 多重if 条件判断 要注意的是 当指定某种情况的时候,条件需要添加 toString() 方法 mybatis常用判断语法(标签) 作为java开发,我们常用的判断有if.switch语句,其实在MyBatis中也有对应的标签,用于动态生成sql语句. 1. if判断 <where>     <if test="null != statusC

  • Java各种锁在工作中使用场景和细节经验总结

    目录 1.synchronized 1.1.共享资源初始化 2.CountDownLatch 2.1.场景 2.2.实现 3.总结 1.synchronized synchronized 是可重入的排它锁,和 ReentrantLock 锁功能相似,任何使用 synchronized 的地方,几乎都可以使用 ReentrantLock 来代替,两者最大的相似点就是:可重入 + 排它锁,两者的区别主要有这些: ReentrantLock 的功能更加丰富,比如提供了 Condition,可以打断的加

随机推荐