不想写大量 if 判断?试试用规则执行器优化,就很丝滑!

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

if (是否海外用户) {return false;
}if (刷单用户) {return false;
}if (未付费用户 && 不再服务时段) {return false
}if (转介绍用户 || 付费用户 || 内推用户) {return true;
}

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

  • 咱们的的主要流程主要是基于 and 或者 or 的关系。

  • 如果有一个不匹配的话,其实咱们后续的流程是不用执行的,就是需要具备一个短路的功能。

  • 对于目前的现状来说,我如果在原有的基础上来改,只要稍微注意一下解决需求不是很大的问题,但是说后面可维护性非常差。

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

2规则执行器

针对这个需求,我首先梳理了一下咱们规则执行器大概的设计, 然后我设计了一个 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;}@Overridepublic boolean execute(RuleDto dto) {return executeRule(convert(dto));}protected <T> boolean executeRule(T t) {return true;}
}// 具体规则- 例子1
public class AddressRule extends AbstractRule {@Overridepublic 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 {@Overrideprotected <T> T convert(RuleDto dto) {NationalityRuleDto nationalityRuleDto = new NationalityRuleDto();if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {nationalityRuleDto.setNationality(MATCH_NATIONALITY_START);}return (T) nationalityRuleDto;}@Overrideprotected <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 关系匹配失败一次,返回 falsereturn false;}}// and 关系全部匹配成功,返回 truereturn true;}private boolean or(RuleDto dto, List<BaseRule> ruleList) {for (BaseRule rule : ruleList) {boolean execute = rule.execute(dto);if (execute) {// or 关系匹配到一个就返回 truereturn true;}}// or 关系一个都匹配不到就返回 falsereturn false;}
}

执行器的调用

public class RuleServiceTest {@org.junit.Testpublic void execute() {//规则执行器//优点:比较简单,每个规则可以独立,将规则,数据,执行器拆分出来,调用方比较规整//缺点:数据依赖公共传输对象 dto//1. 定义规则  init ruleAgeRule ageRule = new AgeRule();NameRule nameRule = new NameRule();NationalityRule nationalityRule = new NationalityRule();AddressRule addressRule = new AddressRule();SubjectRule subjectRule = new SubjectRule();//2. 构造需要的数据 create dtoRuleDto dto = new RuleDto();dto.setAge(5);dto.setName("张三");dto.setAddress("北京");dto.setSubject("数学");;//3. 通过以链式调用构建和执行 rule executeboolean 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);}
}

3总结

规则执行器的优点和缺点

优点:

比较简单,每个规则可以独立,将规则,数据,执行器拆分出来,调用方比较规整;

我在 Rule 模板类中定义 convert 方法做参数的转换这样可以能够,为特定 rule 需要的场景数据提供拓展。

缺点:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/212406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

16ASM 分段和机器码

8086CPU存储分段管理 问题1&#xff1a;8086是16位cpu&#xff0c;最多可访问&#xff08;寻址&#xff09;多大内存&#xff1f; 运算器一次最多处理16位的数据。地址寄存器的最大宽度为16位。访问的最大内存为&#xff1a;216 64K 即 0000 - FFFF。 问题2&#xff1a;808…

Hadoop集群破坏试验可靠性验证

集群环境说明&#xff1a; 准备5台服务器&#xff0c;hadoop1、hadoop2、hadoop3、hadoop4、hadoop5&#xff1b; 分别部署5个节点的zookeeper集群、hadoop集群、hbase集群 本次对于Hadoop集群测试主要分为五个方面&#xff1a; 手动进行datanode节点删除&#xff1a;&#…

typedef 与#define 的区别

typedef 与#define 的区别 typedef &#xff1a; 给一个已经存在的数据类型&#xff08;注意&#xff1a;是类型不是变量&#xff09;取一个别名&#xff0c;而非定义一个新的数据类型 #define宏定义&#xff1a; #define宏定义&#xff1a;在预编译时直接进行简单的文本替换 举…

WIFI直连(Wi-Fi P2P)

一、概述 Wifi peer-to-peer&#xff08;也称Wifi-Direct&#xff09;是Wifi联盟推出的一项基于原来WIfi技术的可以让设备与设备间直接连接的技术&#xff0c;使用户不需要借助局域网或者AP&#xff08;Access Point&#xff09;就可以进行一对一或一对多通信。这种技术的应用…

计算机毕业设计 SpringBoot的乐乐农产品销售系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Xmanager

什么是 XManager Xmanager 是市场上领先的 PC X 服务器&#xff0c;可将X应用程序的强大功能带入 Windows 环境。 提供了强大的会话管理控制台&#xff0c;易于使用的 X 应用程序启动器&#xff0c;X 服务器配置文件管理工具&#xff0c;SSH 模块和高性能 PC X 服务器。 Xman…

javaScript(六):DOM操作

文章目录 1、DOM介绍2、DOM&#xff1a;获取Element对象3、DOM&#xff1a;事件监听3.1、事件介绍3.2、常见事件3.3、设置事件的两种方式3.4、事件案例 1、DOM介绍 概念 Document Object Model &#xff0c;文档对象模型 将标记语言的各个组成部分封装为对应的对象&#xff1a…

Realme X7 Pro Root 刷机教程

Realme X7 Pro 刷机教程 Just For Fun&#xff0c;最近倒腾了下Realme X7 Pro 刷root。此博客为个人记录刷机过程&#xff0c;如有机友跟随本教程操作&#xff0c;请谨慎操作&#xff01;&#xff01;&#xff01; 以下教程真针对Realme X7 Pro&#xff0c;其他版本方法未知&…

springboot(ssm高校竞赛管理系统 在线竞赛平台 Java系统

springboot(ssm高校竞赛管理系统 在线竞赛平台 Java系统 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09; 数…

qt 模型视图结构

在Qt中&#xff0c;Model、View和Delegate三者之间的关系如下&#xff1a; Model&#xff08;模型&#xff09;&#xff1a;Model是数据的抽象表示&#xff0c;它提供了一种结构化的方式来存储和管理数据。Model负责维护数据的状态&#xff0c;并提供接口供其他组件&#xff08…

【Flutter】vs2022上开发flutter

在vs上开发flutter&#xff0c;结果扩展仓库上没办法找到Dart&#xff0c;Flutter。 在 这 搜索Dart时也无法找到插件。 最后发现是安装工具出错了 安装了 开发需要的是

挖漏洞之文件上传

&#xff08;一&#xff09;漏洞原理 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。…

从线性回归到神经网络

目录 一、线性回归关键思想 1、线性模型 2、基础优化算法 二、线性回归的从零开始实现 1、生成数据集 2、读取数据集 3、初始化模型参数 4、定义模型 5、定义损失函数 6、定义优化算法 7、训练 三、线性回归的简洁实现 1、生成数据集 2、读取数据集 3、定义模型…

论文代码阅读:TGN模型训练阶段代码理解

文章目录 [toc] TGN模型训练阶段代码理解论文信息代码过程手绘代码训练过程compute_temporal_embeddingsupdate_memoryget_raw_messagesget_updated_memoryself.message_aggregator.aggregateself.memory_updater.get_updated_memoryMemoryget_embedding_moduleGraphAttentionE…

什么是W3C标准? 什么要遵循?

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍HTML5中W3C的标准&#xff0c;需要遵循的规则以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问…

【AIGC】Midjourney高级进阶版

Midjourney 真是越玩越上头&#xff0c;真是给它的想象力跪了~ 研究了官方API&#xff0c;出一个进阶版教程 命令 旨在介绍Midjourney在Discord频道中的文本框中支持的指令。 1&#xff09;shorten 简化Prompt 该指令可以将输入的Prompt为模型可以理解的语言。模型理解语言…

Git初学入门指令

git基本指令 初始化&#xff1a; git init查看状态&#xff1a; git status新建文件&#xff1a; touch <filename>加入暂存区&#xff1a; git add . 或者 git add -A 表示全部加入暂存区 git add <filename>单个文件加入暂存区加入仓库&#xff1a; …

PCIe中断总结-各个中断的区别

1.简介&#xff1a; PCIe中断支持三种传输方式&#xff1a; • Legacy: 也称传统中断&#xff0c;Legacy PCI中断机制,每个PCI设备最多支持四个中断信号(边带信号:INTA# INTB# INTC# INTD#) • MSI(Message Signaled Interrupt): Post Memory Write,只支持32个中断向量 • MSI…

力扣labuladong一刷day35天

力扣labuladong一刷day35天 文章目录 力扣labuladong一刷day35天一、98. 验证二叉搜索树二、700. 二叉搜索树中的搜索三、701. 二叉搜索树中的插入操作四、450. 删除二叉搜索树中的节点 一、98. 验证二叉搜索树 题目链接&#xff1a;https://leetcode.cn/problems/validate-bi…

【Linux】如何对文本文件进行有条件地划分?——cut命令

cut 命令可以根据一个指定的标记&#xff08;默认是 tab&#xff09;来为文本划分列&#xff0c;然后将此列显示。 例如想要显示 passwd 文件的第一列可以使用以下命令&#xff1a;cut –f 1 –d : /etc/passwd cut&#xff1a;用于从文件的每一行中提取部分内容的命令。-f 1&…