java设计模式之策略模式实操

一、背景
临床服务项目流向规则匹配,比如说医生开一个“CT”检查,该检查应该由哪个科室来执行,是通过流向规则配置来决定的,具体配置如下图:
在这里插入图片描述
通过相关的条件匹配,最终找到流向科室。
二、设计思路
有几个注意的点:
(1)条件可能会变化,比如增加条件,减少条件;
(2)条件可以单选、多选、输入字符串,也就是说条件值可能是等于、包含、不等于、不包含、大于、小于、自定义输入值;
如何来设计更好的满足以上需求,从以下几个方面:
(1)表结构层面:既然条件有可能变化,那么条件名称和条件值不能设计成一个个固定的字段,这样如果如果增减或者减少条件就不必要去修改表结构;那么具体怎么设计呢?表结构设计成通用结构,包含三个主要字段:条件类型编码、条件名称、条件值;如果一个条件配置来两个或以上值,那么在表里面就对应了多条记录;
(2)代码设计模式:工厂模式+策略模式,每个配置的条件都需要去匹配,而每个条件的匹配可能相同或者不同,所以可以定义一个抽象类作为父类,每一个条件创建一个类,继承这个抽象类,抽象类主要有三个抽象方法:获取匹配器的类型代码、获取传入对象参数中该匹配器对应的入参值、条件匹配;通过工厂模式将所有匹配器进行初始化;
三、相关类定义
1、匹配器抽象类:获取匹配器的类型代码、是否自定义匹配算法、获取传入对象参数中该匹配器对应的入参值、条件匹配;
2、匹配器实现类一,配置了单个条件值;
3、匹配器实现类二,配置了多个条件值;
4、匹配器实现类三,自定义解析条件值并返回;
5、工厂类:批量创建匹配器实例;
6、匹配器持有类:对匹配器进行相关调度操作;
7、工具类:条件匹配;
四、类的详解
1、匹配器抽象类:CliFlowRuleMatcher

    /*** 获取条件类型代码,表示我是哪个条件,由子类去实现* @return*/protected abstract Long getConditionTypeCode();/*** 是否自定义匹配器* @return bool值*/public boolean isCustomMatcher();
/*** 规则匹配* @param valueSet 配置值* @param regularOperationCode 运算符* @param condition 入参对象* @return 匹配结果*/public boolean matchDefaultValue(Collection<Long> valueSet, FlowRuleCoreExtInputDTO condition, Long regularOperationCode) {// 先匹配单值Long value = singleValueGetter().apply(condition);if (Objects.nonNull(value)) {return MatchUtil.match(valueSet, value, regularOperationCode);}// 单值没实现再匹配多值Collection<Long> values = multiValueGetter().apply(condition);if (CollectionUtil.isNotEmpty(values)) {return MatchUtil.match(valueSet, values, regularOperationCode);}return true;}/*** 自定义结果 规则匹配* @param customizeValSet* @param condition* @param regularOperationCode* @return*/public boolean matchCustomizeValue(Collection<String> customizeValSet, FlowRuleCoreExtInputDTO condition, Long regularOperationCode) {// 先匹配单值Collection<String> value = singleCustomizeValueGetter().apply(condition);if (CollectionUtil.isNotEmpty(value)) {return MatchUtil.matchCustomizeValue(customizeValSet, value, regularOperationCode);}// 单值没实现再匹配多值Collection<String> values = multiCustomizeValueGetter().apply(condition);if (CollectionUtil.isNotEmpty(values)) {return MatchUtil.matchCustomizeValue(customizeValSet, values, regularOperationCode);}return true;}

2、条件匹配实现类一(单个条件值):BuIdMatcher

@Component
public class BuIdMatcher extends CliFlowRuleMatcher {@Overridepublic Long getConditionTypeCode() {return ConditionDeShortNameEnum.PRESCRIBED_BU_ID.getValue();}@Overridepublic Function<FlowRuleCoreExtInputDTO, Long> singleValueGetter() {return FlowRuleCoreExtInputDTO::getBuId;}
}

3、条件匹配实现类二(多个条件值):CsTypeCodeMatcher

@Component
public class CsTypeCodeMatcher extends CliFlowRuleMatcher {@Overridepublic Long getConditionTypeCode() {return ConditionDeShortNameEnum.CS_TYPE_CODE.getValue();}@Overrideprotected Function<FlowRuleCoreExtInputDTO, Collection<Long>> multiValueGetter() {return FlowRuleCoreExtInputDTO::getCsTypeCodeList;}
}

4、条件匹配实现类三(自定义获取配置的条件):RealIPMatcher

@Component
public class RealIPMatcher extends CliFlowRuleMatcher {@Overridepublic boolean isCustomMatcher() {return true;}@Overridepublic Long getConditionTypeCode() {return ConditionDeShortNameEnum.REAL_IP.getValue();}@Overrideprotected Function<FlowRuleCoreExtInputDTO, Collection<String>> singleCustomizeValueGetter() {return this::getRealIp;}private Collection<String> getRealIp(FlowRuleCoreExtInputDTO ruleConditionDTO){if (StringUtil.isNotEmpty(ruleConditionDTO.getRealIp())){return Arrays.asList(ruleConditionDTO.getRealIp().split(";"));}return ListUtil.emptyList();}
}

5、工厂类:CliFlowRuleMatcherFactory

@Component
public class CliFlowRuleMatcherFactory {private final Map<Long, CliFlowRuleMatcher> execDefinitionMatcherMap = new HashMap<>();@Autowired(required = false)public CliFlowRuleMatcherFactory(List<CliFlowRuleMatcher> execDefinitionMatchers) {if (CollectionUtil.isNotEmpty(execDefinitionMatchers)) {execDefinitionMatchers.forEach(execDefinitionMatcher ->execDefinitionMatcher.getConditionDeShortNames().forEach(conditionDeShortName ->execDefinitionMatcherMap.put(conditionDeShortName, execDefinitionMatcher)));}}public CliFlowRuleMatcher getByConditionDeShortName(Long conditionDeShortName) {return execDefinitionMatcherMap.get(conditionDeShortName);}
}

6、策略对象的持有类:xXxService

private boolean matchCondition(FlowRuleCoreExtInputDTO condition, CliFlowRuleOutputDTO clinicalOrderFlowRule){int successCount = 0;// 若匹配条件不存在,等于直接匹配上Map<Long, List<CliFlowConditionOutputDTO>> flowConditionMap = clinicalOrderFlowRule.getClinicalOrderFlowConditionList().stream().collect(Collectors.groupingBy(CliFlowConditionOutputDTO::getConditionDeShortName));for (Map.Entry<Long, List<CliFlowConditionOutputDTO>> entry : flowConditionMap.entrySet()) {CliFlowRuleMatcher matcher = this.cliFlowRuleMatcherFactory.getByConditionDeShortName(entry.getKey());if (Objects.isNull(matcher)) {// 没有匹配器successCount++;continue;}if (matcher.isCustomMatcher()) {Set<String> valueSetDesc = entry.getValue().stream().map(CliFlowConditionOutputDTO::getConditionValueName).collect(Collectors.toSet());if (matcher.matchCustomizeValue(valueSetDesc, condition, RegularOperationCodeEnum.LIKE.getCode())) {// 每个元短名配置匹配成功后加1successCount++;}}else{Set<Long> valueSet = entry.getValue().stream().map(CliFlowConditionOutputDTO::getConditionValue).collect(Collectors.toSet());if (matcher.matchDefaultValue(valueSet, condition, RegularOperationCodeEnum.CONTAIN.getCode())) {// 每个元短名配置匹配成功后加1successCount++;}}}return successCount == flowConditionMap.size();}

7、工具类:MatchUtil

/*** 配置值是否包含匹配值* @param configValues 配置值* @param matchValue 匹配值* @param regularOperationCode 运算符* @return 是否匹配*/public static boolean match(Collection<Long> configValues, Long matchValue, Long regularOperationCode) {if (CollectionUtil.isEmpty(configValues) || Objects.isNull(matchValue) || Objects.isNull(regularOperationCode)) {return false;}// 等于if (Objects.equals(RegularOperationCodeEnum.EQUAL.getCode(), regularOperationCode)) {if (configValues.size() > 1) {return false;}return Objects.equals(configValues.iterator().next(), matchValue);}// 不等于if (RegularOperationCodeEnum.NOT_EQUAL.getCode().equals(regularOperationCode)) {if (configValues.size() > 1) {return false;}return !Objects.equals(configValues.iterator().next(), matchValue);}// 包含if (RegularOperationCodeEnum.CONTAIN.getCode().equals(regularOperationCode)) {return configValues.contains(matchValue);}// 不包含if (RegularOperationCodeEnum.NOT_CONTAIN.getCode().equals(regularOperationCode)) {return !configValues.contains(matchValue);}return false;}

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

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

相关文章

RTC的基本概念以及相关例程

实时时钟(RTC) 北京时间跟伦敦时间错8个小时 BKP简介 BKP本质上是RAM存储器&#xff0c;没有掉电不丢失的能力。 VBAT的作用就是&#xff0c;当VDD断电时&#xff0c;BKP会切换到VBAT供电&#xff0c;这样可以继续维持BKP里面的数据&#xff0c;如果VDD断电&#xff0c;VBAT也…

开源博客项目Blog .NET Core源码学习(15:App.Hosting项目结构分析-3)

本文学习并分析App.Hosting项目中前台页面的关于本站页面和点点滴滴页面。 关于本站页面 关于本站页面相对而言布局简单&#xff0c;与后台控制器类的交互也不算复杂。整个页面主要使用了layui中的面包屑导航、选项卡、模版、流加载等样式或模块。   面包屑导航。使用layui…

分布式结构化数据表Bigtable

文章目录 设计动机与目标数据模型行列时间戳 系统架构主服务器Chubby作用子表服务器SSTable结构子表实际组成子表地址组成子表数据存储及读/写操作数据压缩 性能优化局部性群组&#xff08;Locality groups&#xff09;压缩布隆过滤器 Bigtable是Google开发的基于GFS和Chubby的…

CADMap3D2024 2023下载地址及安装教程

CAD Map 3D是由Autodesk开发的一款专业的地图制作和GIS&#xff08;地理信息系统&#xff09;软件。它是AutoCAD系列软件的一个扩展&#xff0c;提供了一系列特定于地理数据的工具和功能。 CAD Map 3D主要用于处理和管理与地理空间相关的数据&#xff0c;在地图制作、城市规划…

算法中的复杂度(先做个铺垫)

文章目录 定义与分类时间复杂度概念大O的渐进表示法举例情况注意内涵 空间复杂度最优解 定义与分类 复杂度&#xff1a;衡量算法效率的标准时间效率&#xff1a;衡量这个算法的运行速度&#xff0c;也就是我们常说的时间复杂度空间效率&#xff1a;衡量这个算法所需要的额外空…

Vue项目实战:基于用户身份的动态路由管理

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

Spring Boot | Spring Boot中进行 “文件上传” 和 “文件下载”

目录: 一、SpringBoot中进行 " 文件上传" :1.编写 "文件上传" 的 “表单页面”2.在全局配置文件中添加文件上传的相关配置3.进行文件上传处理&#xff0c;实现 "文件上传" 功能4.效果测试 二、SpringBoot中进行 "文件下载" :“英文名称…

UI设计/交互设计/视觉设计项目汇报/作品集Figma/PPT模板

作为UI设计/交互设计/视觉设计师&#xff0c;创建作品集对于向潜在客户或雇主展示您的技能、创造力和风格至关重要。以下分步指南可帮助您创建令人印象深刻的作品集&#xff1a; 选择您的最佳作品&#xff1a;选择您最强大且最相关的设计项目&#xff0c;将其纳入您的作品集。…

正则表达式:特殊序列(五)

正则表达式中的特殊序列包括&#xff1a;1. \d&#xff1a;匹配任意数字字符&#xff0c;等同于[0-9]。2. \D&#xff1a;匹配任意非数字字符&#xff0c;等同于[^0-9]。3. \w&#xff1a;匹配任意字母、数字或下划线字符&#xff0c;等同于[A-Za-z0-9_]。4. \W&#xff1a;匹配…

C语言简单的数据结构:单链表的有关算法题(2)

题目&#xff1a; 4. 单链表相关经典算法OJ题3&#xff1a;合并两个有序链表5. 循环链表经典应⽤-环形链表的约瑟夫问题6. 单链表相关经典算法OJ题5&#xff1a;分割链表 接着我们介绍后面的三道题&#xff0c;虽然代码变多了但我们的思路更加通顺了 4. 单链表相关经典算法OJ题…

【JavaEE多线程】理解和管理线程生命周期

目录 ThreadThread类的常用构造方法Thread类的常见属性启动一个线程-start()终止一个线程等待一个线程-join()线程的状态 Thread Thread 就是在 Java 中&#xff0c;线程的代言人。系统中的一个线程&#xff0c;就对应到 Java 中的一个 Thread 对象。围绕线程的各种操作&#…

971: 统计利用先序遍历创建的二叉树的深度

解法&#xff1a; 1.先序遍历创建二叉树链表形式 2.求二叉树的深度 用后序遍历实现&#xff1a; 1.后序遍历求节点A左右子树高度 2.对节点A&#xff1a; 1.取左右子树较大高度 2.返回高度1&#xff08;即以节点A为根节点的子树的最大深度&#xff09; 例如 #include <ios…