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

devtools/2024/9/22 14:58:21/

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

java">    /*** 获取条件类型代码,表示我是哪个条件,由子类去实现* @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

java">@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

java">@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

java">@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

java">@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

java">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

java">/*** 配置值是否包含匹配值* @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.ppmy.cn/devtools/7380.html

相关文章

【PyTorch】1-基础知识(张量、导数、CUDA)

PyTorch&#xff1a;1-基础知识 注&#xff1a;所有资料来源且归属于thorough-pytorch(https://datawhalechina.github.io/thorough-pytorch/)&#xff0c;下文仅为学习记录 1.1&#xff1a;张量 神经网络核心包&#xff1a;autograd&#xff08;自动微分&#xff09; 张量…

在线拍卖系统,基于SpringBoot+Vue+MySql开发的在线拍卖系统设计和实现

目录 一. 系统介绍 二. 功能模块 2.1. 管理员功能模块 2.2. 用户功能模块 2.3. 前台首页功能模块 2.4. 部分代码实现 一. 系统介绍 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系…

electron项目打包慢、打包报错

项目使用了electron框架&#xff0c;在第一次打包或者网络条件不好的环境下进行打包时熟速度慢的出奇&#xff0c;甚至经常出现打包失败的情况&#xff08;如上面图片的报错&#xff09;。 这是因为&#xff0c;在electron打包的过程中&#xff0c;需要去官方源https://github.…

05集合-CollectionListSet

Collection体系的特点、使用场景总结 如果希望元素可以重复&#xff0c;又有索引&#xff0c;索引查询要快? 用ArrayList集合, 基于数组的。(用的最多) 如果希望元素可以重复&#xff0c;又有索引&#xff0c;增删首尾操作快? 用LinkedList集合, 基于链表的。 如果希望增…

【Ansible】02

【Ansible】01 Ansible playbook 剧本 ansible-playbook 常用于复杂任务的管理管理经常要完成的任务playbook也是通过模块和它的参数 , 在特定主机上执行任务playbook是一个文件 , 该文件中需要通过yaml格式进行书写将经常需要执行的任务写入一个文件剧本/文件中可以包换多…

什么是RAG?

RAG是“Retrieval-Augmented Generation”的缩写&#xff0c;这是一种自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;用于增强生成式模型的性能&#xff0c;尤其是在问答、文本摘要、对话系统等任务中。RAG结合了检索&#xff08;Retrieval&#xff09;和生成&#…

【创建型模式】原型模式

一、原型模式概述 原型&#xff08;Prototype&#xff09;模式的定义&#xff1a;用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里&#xff0c;原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效&#xf…

【JavaEE初阶】网络原理|认识协议|协议分层|TCP/IP模型|封装和分用

一、认识协议 1.概念 简单来说&#xff1a;就是一种通信双方&#xff0c;对于通信规则的约定&#xff08;标准&#xff09;&#xff0c;一定是通信双方都认可的 但是这个协议不一定是认可面非常广的&#xff0c;即使是两个人之间的也可叫做协议 就好⽐⻅⽹友&#xff0c;彼此…