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

news2024/11/17 13:34:49

一、背景
临床服务项目流向规则匹配,比如说医生开一个“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 {

    @Override
    public Long getConditionTypeCode() {
        return ConditionDeShortNameEnum.PRESCRIBED_BU_ID.getValue();
    }

    @Override
    public Function<FlowRuleCoreExtInputDTO, Long> singleValueGetter() {
        return FlowRuleCoreExtInputDTO::getBuId;
    }
}

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

@Component
public class CsTypeCodeMatcher extends CliFlowRuleMatcher {

    @Override
    public Long getConditionTypeCode() {
        return ConditionDeShortNameEnum.CS_TYPE_CODE.getValue();
    }

    @Override
    protected Function<FlowRuleCoreExtInputDTO, Collection<Long>> multiValueGetter() {
        return FlowRuleCoreExtInputDTO::getCsTypeCodeList;
    }
}

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

@Component
public class RealIPMatcher extends CliFlowRuleMatcher {

    @Override
    public boolean isCustomMatcher() {
        return true;
    }

    @Override
    public Long getConditionTypeCode() {
        return ConditionDeShortNameEnum.REAL_IP.getValue();
    }

    @Override
    protected 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())) {
                    // 每个元短名配置匹配成功后加1
                    successCount++;
                }
            }else{
                Set<Long> valueSet = entry.getValue().stream().map(CliFlowConditionOutputDTO::getConditionValue).collect(Collectors.toSet());
                if (matcher.matchDefaultValue(valueSet, condition, RegularOperationCodeEnum.CONTAIN.getCode())) {
                    // 每个元短名配置匹配成功后加1
                    successCount++;
                }
            }
        }
        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.coloradmin.cn/o/1594975.html

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

相关文章

云计算:Linux 部署 OVN 集群

目录 一、实验 1.环境 2.Linux 部署 OVN 集群&#xff08;中心端&#xff09; 3.Linux 部署 OVN 集群&#xff08;业务端1&#xff09; 4.Linux 部署 OVN 集群&#xff08;业务端2&#xff09; 4.OVN 中心端 连接数据库 5.OVN 业务端1 加⼊控制器 6.OVN 业务端2 加⼊控…

AI克隆语音(基于GPT-SoVITS)

概述 使用GPT-SoVITS训练声音模型&#xff0c;实现文本转语音功能。可以模拟出语气&#xff0c;语速。如果数据质量足够高&#xff0c;可以达到非常相似的结果。相比于So-VITS-SVC需要的显卡配置更低&#xff0c;数据集更小&#xff08;我的笔记本NVIDIA GeForce RTX 4050 Lap…

基于LSTM的新闻中文文本分类——基于textCNN与textRNN

构建词语字典 def build_vocab(file_path, tokenizer, max_size, min_freq):# 定义词汇表字典&#xff1a;使用 vocab_dic {} 初始化一个空字典&#xff0c;用于存储每个词及其出现频率vocab_dic {}with open(file_path, r, encodingUTF-8) as f:for line in tqdm(f):lin l…

为什么光伏探勘测绘需要无人机?

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业也迎来了快速发展的机遇。光伏电站作为太阳能发电的主要形式之一&#xff0c;其建设前期的探勘测绘工作至关重要。在这一过程中&#xff0c;无人机技术的应用正逐渐展现出其独特的优势。那么&#xff0c;为什么光伏探勘…

《手机维修600G资料》云盘下载地址

无意中发现一个生财之道&#xff0c;哈哈哈&#xff0c;就是发现有人在一些视频平台&#xff0c;发手机维修之类的视频吸引客户。这样自己就不用开店也可以接生意了。问题剩下就一个了&#xff0c;把手机维修技术学好&#xff0c;一技在手&#xff0c;天上我有。 《手机维修600…

有条件的打破IBGP水平分割----反射规则和联邦+实验举例

背景&#xff1a;在一个AS中的设备运行了BGP协议&#xff0c;那么正常应该都连接了其他的AS&#xff0c;存在EBGP邻居关系&#xff1b;又由于IBGP的水平分割规则&#xff0c;导致从外部学习到的路由传递给本地AS时&#xff0c;需要和本地AS中运行BGP协议都要建立IBGP邻居关系&a…

基于R语言实现的负二项回归模型【理解与实现】-理解负二项回归模型和泊松回归模型之间的区别

前言 我们可以在R语言中使用MASS包中的glm.nb函数来拟合负二项模型&#xff0c;以及使用glm函数来拟合泊松模型。以下是一个详细的过程&#xff0c;包括模拟数据的生成、模型的拟合、结果的比较和解释。 需要的包 if (!require("MASS")) install.packages("M…

ES增强框架easy-es

因为最近做的功能是关于舆情的,所以数据量比较大的,本来打算用MySQL做时间分表来做,但是经过一段时间的测试,发现数据量太大,用时间分表不能满足性能的要求,所以决定将数据存储改为ES,但是短时间内改底层框架又不是一个小工程,时间上不允许,所以找到了一个很合适的框架,他跟myb…

Echarts简单的多表联动效果和添加水印和按钮切换数据效果

多表联动 多表联动效果指的是在多个表格之间建立一种交互关系&#xff0c;以便它们之间的操作或选择能够相互影响。通常情况下&#xff0c;多表联动效果可以通过以下方式之一实现&#xff1a; 数据关联&#xff1a; 当在一个表格中选择或操作某些数据时&#xff0c;另一个表格…

DataGrip连接Docker中的MySQL容器

获取MySQL镜像 通过命令行工具或者docker desktop 命令行&#xff1a; docker pull mysqldocker desktop工具&#xff0c;tag可以指定版本 创建mysql容器 我们知道dockerfile用于编写镜像&#xff0c;dockercompose用于编排容器&#xff0c;所以这里我用dockercompose来创…

eNSP防火墙配置实验(trust、DMZ、untrust)

【拓扑】 设备 接口 IP地址/子网掩码/网关 AR1 G0/0/0 10.1.3.2/24 G0/0/1 100.1.1.2/24 FW1 G0/0/0 192.168.166.254/24 G1/0/0 10.1.1.1/24&#xff0c;trust域 G1/0/1 10.1.2.1/24&#xff0c;DMZ域 G1/0/2 100.1.3.1/24&#xff0c;untrust域 LSW1 G0/0/…

ssm051网上医院预约挂号系统+jsp

网上医院预约挂号系统设计与实现 摘 要 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让医院预约挂号信息的管理模式进行升级&#xff0c;也为了更好的维护医院预约挂号信息&#xff0c;网上医院…

13.多通道视频流缓存以及显示架构

1 简介 多通道视频流缓存以及显示架构是一个在数字图像处理中很基础也很重要的一个架构。在图像拼接以及高分辨率图像显示方面应用范围较为广泛。本文将介绍一个四通道的图像显示。可以四个图像信息输入以及拼接到一个显示屏里面。使用的开发板为A7 2 框架图 架构图如下图所示…

Day20-【Java SE高级】单元测试 反射 注解 动态代理

一、单元测试 就是针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试。 1. 咱们之前是如何进行单元测试的?有啥问题? 只能在main方法编写测试代码&#xff0c;去调用其他方法进行测试。无法实现自动化测试&#xff0c;一个方法测试失败&#xff0c;可能…

FJSP:水鹿优化算法(Sambar Optimization Algorithm,SOA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

什么是 MVVM、mvc 模型

mvc模型 MVC: MVC 即 model-view-controller&#xff08;模型-视图-控制器)是项目的一种分层架构思想&#xff0c;它把复杂的业务逻辑&#xff0c; 抽离为职能单一的小模块&#xff0c;每个模块看似相互独立&#xff0c;其实又各自有相互依赖关系。它的好处是&#xff1a;保证了…

【信道编码】1 无线通信发展历程与挑战、信道分类、多径信道、单径信号传输与检测

【信道编码】1 无线通信发展历程与挑战、信道分类、多径信道、单径信号传输与检测 写在最前面无线通信发展历程一、电磁波的发现与利用&#xff08;19世纪末至20世纪初&#xff09;二、无线电技术的广泛应用&#xff08;20世纪初至20世纪中叶&#xff09;三、数字化与移动通信的…

HTML重要标签重点及属性(表格表单列表)——之转生在异世界学前端

表格标签 table是用于定义表格的标签 tr是用于定义表格的行 td是用来定义表格的列&#xff0c;th是表头一般只有一个表头会加粗 表格属性border是设置边框值为1;1是有边框&#xff0c; align设置居中对齐方式center&#xff0c;left&#xff0c;right cellpadding设置文字…

如何下载和安装Google Chrome扩展插件:一步步指南

Google Chrome 插件为我们提供了这样的便利&#xff0c;但有时找到一个有用的插件后&#xff0c;我们可能需要将其下载到本地以便离线使用或备份。 一、为什么可以从Google Chrome商店直接下载插件&#xff1f; Google Chrome 扩展插件主要通过Chrome Web Store分发&#xff…

万兆以太网MAC设计(4)CRC_process模块

文章目录 前言一、模块功能二、实现过程三、仿真总结 前言 上文介绍的MAC_RX模块当中增加了CRC校验和比对的功能&#xff0c;本文将根据CRC校验的结果&#xff0c;来决定将数据输出到上层用户还是丢弃。 一、模块功能 接收MAC_RX模块输出的AXIS数据&#xff0c;存入本地环形…