java实现同个接口多个实现类通用策略模式

项目业务中,有多个平台,多个平台直接有相同的业务,只有一个接口入口,但是
不同的平台入口,虽然接口相同,参数相同,但是各自的具体实现不同,唯一能区分来源的
是请求头中有标识平台的字段:from
最简单的方法是对from进行判断,
if(from==1){//执行平台1的方法
}
if(from==2){//执行平台2的方法
}
......
虽然这样也能实现,但是明显多余,且不好扩展,我们只需要关注与具体业务实现即可
通过from标识,来自动判断执行具体的实现方法
思路:
1、定义个通用的策略实现方法,spingboot注入的时候扫描到哪些类是需要多实现的
2、需要多实现的每个实现类标记下平台的自定义注解,用于识别from具体执行的类

策略父类

定义父类,用于多实现的类能被扫描到
/*** 基础策略,需要进行策略分发的接口类,就要继承这个接口* 方便统一注入管理*/
public interface BaseStrategy {}/*** 所属平台注解* 用于标识类所属平台*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SysPlatform {/*** 所属平台,自定义的平台枚举,根据自己业务来,可以是 123 数字等,不一定是要枚举* 枚举好管理*/SysPlatformConstant.SysPlatformEnum from() default SysPlatformConstant.SysPlatformEnum.ALL;}/*** 围栏服务接口,提供围栏相关的操作功能* 继承基础策略**/
public interface IFenceService  extends BaseStrategy {/*** 更新围栏信息** @param fence 围栏更新信息*/void updateFence(IUpdateFenceVO fence);
}/*** 围栏服务具体实现类1* 实现IFenceService**/
@Slf4j
@Service
@RequiredArgsConstructor
//这个是自定义注解,标记这个实现类是这个平台的标识,靠这个注解来识别执行具体的实现类
@SysPlatform(from = SysPlatformConstant.SysPlatformEnum.AGRICULTURE_PLATFORM)
public class AgrFenceServiceImpl implements IFenceService {/*** 更新围栏** @param fence*/@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类1");}
}/*** 围栏服务具体实现类2*/
@Slf4j
@Service
@RequiredArgsConstructor
//这个没有使用自定义注解,@SysPlatform 用于无法识别是,走这个通用实现
@Primary
public class FenceServiceImpl  implements IFenceService {/*** 更新围栏** @param fence*/@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类2");}
}
/*** 围栏服务具体实现类3*/
@Slf4j
@Service
//这个是自定义注解,标记这个实现类是这个平台的标识,靠这个注解来识别执行具体的实现类
@SysPlatform(from = SysPlatformConstant.SysPlatformEnum.ELDER_PLATFORM)
public class ElderFenceServiceImpl implements IFenceService {/*** 更新围栏** @param fence*/@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类3");}
}

策略实现具体服务上下文代码

/*** 基本策略上下文,用于具体分发接口到哪个实现类,执行多实现的具体方法*/
@Component
@RequiredArgsConstructor
@Slf4j
public class BaseStrategyContext {/*** 所有产品策略集合,spring自动注入*/@Autowired(required = false)private List<BaseStrategy> productStrategyList;private static BaseStrategyContext baseStrategyContext;/*** 初始化时已全部注入,赋值给静态变量baseStrategyContext*/@PostConstructpublic void init() {baseStrategyContext = this;baseStrategyContext.productStrategyList = this.productStrategyList;}/*** 选择产品策略** @param parent 来源* @return 对应服务层策略*/public static <T> T build(Class<T> parent) {// 接收到请求,记录请求内容HttpServletRequest request = WebUtil.getRequest();String fromType = request.getHeader(SecurityConstant.OLD_FROM);return getRunServiceClass(parent, fromType);}/*** 选择产品策略** @param parent   接口类,由该类来获取实现该接口的全部子类* @param fromType 来源* @return 对应服务层策略*/public <T> T create(Class<T> parent, String fromType) {return getRunServiceClass(parent, fromType);}private static <T> T getRunServiceClass(Class<T> parent, String fromType) {SysPlatformConstant.UserFromEnum byFromType = SysPlatformConstant.UserFromEnum.getByFromType(fromType);List<Class<?>> subClasses = findSubClasses(parent);T productStrategy = null;for (Class<?> subClass : subClasses) {//获取类上所属平台的注解,有指定平台就按指定实现走,没有就是通用if (subClass.getAnnotation(SysPlatform.class) != null) {SysPlatform annotation = subClass.getAnnotation(SysPlatform.class);SysPlatformConstant.SysPlatformEnum from = annotation.from();if (from.getPlatformId().equals(byFromType.getPlatformEnum().getPlatformId())) {productStrategy = (T) SpringUtil.getBean(subClass);break;}} else {productStrategy = (T) SpringUtil.getBean(subClass);}}AssertUtil.notNull(productStrategy, CustomReturnEnum.NOT_ALLOW_OPERATION);return productStrategy;}/*** 根据传进来的父类,获取所有子类** @param parent* @return*/private static List<Class<?>> findSubClasses(Class<?> parent) {List<Class<?>> subclasses = new ArrayList<>();// 假设我们知道所有类的名称for (BaseStrategy t : baseStrategyContext.productStrategyList) {try {Class<?> clazz = t.getClass();if (parent.isAssignableFrom(clazz) && !clazz.equals(parent)) {subclasses.add(clazz);}} catch (Exception e) {log.error("基础策略上下文错误:{}", ExceptionUtil.getStackStr(e));}}return subclasses;}}

具体的实现方法示例

方法1,用BaseStrategyContext 的create方法//controller层 注入 基本策略上下文private final BaseStrategyContext baseStrategyContext;/*** 查询步数** @param iStepStatisticVO* @return*/@GetMapping("/listStepNum")public OStepMiniappStaticsVO listStepNum(IStepStatisticVO iStepStatisticVO) {//具体当前的来源String from = UserUtil.getFrom();//StepService.class 这个就是要继承BaseStrategy的接口类return baseStrategyContext.create(StepService.class, from).listStepNum(iStepStatisticVO);}----------------------------------------------------------------------------------方法2,用BaseStrategyContext 的build 静态方法,
使用静态方法,controller层不用注入基本策略上下文,可以直接使用/*** 修改围栏信息** @param fence*/@PostMapping("/update")public void updateById(@RequestBody @Valid IUpdateFenceVO fence) {//IFenceService.class 这个就是要继承BaseStrategy的接口类//updateFence 是IFenceService 这个接口里面需要定义的实现方法BaseStrategyContext.build(IFenceService.class).updateFence(fence);}

在这里插入图片描述

通过枚举的方式也能多实现不同的方式

业务背景:相同的数据,但是不同的客户,具体的实现是不一样的,通过客户代码去区分,走不同的具体实现
    /*** MQ监听到的批量推送数据** @param resultList*/private void pushData(List<HealthPushVO> resultList) {//根据租户进行分组Map<Long, List<HealthPushVO>> pushMap = resultList.stream().collect(Collectors.groupingBy(HealthPushVO::getTenantId));pushMap.forEach((tenantId, value) -> {//根据租户获取对应的具体实现类ListenerTableEnum customPush = ListenerTableEnum.getByValue(tenantId.toString());BaseMqProducer producer = SpringUtil.getBean(customPush.getServiceName());producer.healthPush(value, tenantId);});}
/*** 客户配置枚举类**/
@Getter
@AllArgsConstructor
public enum ListenerTableEnum {ZF160("ZF160", "ZF160Push", "ZF160"),ZF161("ZF161", "ZF161Push", "ZF161"),...................public static ListenerTableEnum getByValue(String type) {if (type == null) {return ZF160;}for (ListenerTableEnum val : values()) {if (val.customCode.equals(type)) {return val;}}return ZF160;}/*** 客户代码*/private final String customCode;/*** 服务映射名称*/private final String serviceName;/*** 租户名称*/private final String customName;
}/*** 父类**/
public interface BaseMqProducer {/*** 推送数据** @param oCardCallBackVOS* @param tenantId* @return*/void pushData(List<HealthPushVO> oCardCallBackVOS, Long tenantId);
}/*** 实现父类的具体方法**/
@Slf4j
//指定实现类的名称,这个名称和枚举上的名称要一致,不然无法识别
@Component("ZF160Push")
@RequiredArgsConstructor
public class ZF160Producer implements BaseMqProducer {@Overridepublic void pushData(List<HealthPushVO> oCardCallBackVO, Long tenantId) {}
}/*** 实现父类的具体方法**/
@Slf4j
//指定实现类的名称,这个名称和枚举上的名称要一致,不然无法识别
@Component("ZF161Push")
@RequiredArgsConstructor
public class ZF161Producer implements BaseMqProducer {@Overridepublic void pushData(List<HealthPushVO> oCardCallBackVO, Long tenantId) {}
}

在这里插入图片描述

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

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

相关文章

leetcode-139. 单词拆分-C

暴力回溯回溯过程就是一个决策树模型&#xff0c;从所有选择中找到合适的继续&#xff0c;否则回到上一级继续。该方法思路简单&#xff0c;时间复杂度过高&#xff0c;大概1/4的用例超时。 bool backtrack(char *s, int cur, char** wordDict, int wordDictSize) {// 基线条件…

《彩色终端》诗解——ANSI 艺术解码(DeepSeek)

AIi诗解通吾灵&#xff0c;直抄原文享分玲。 笔记模板由python脚本于2025-08-18 23:35:59创建&#xff0c;本篇笔记适合喜欢诗&代码的coder翻阅。 学习的细节是欢悦的历程 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述。 Python官网…

抓包工具tcpdump详细指南

目录 1. 核心功能与特性 2. 关键参数速查表 3. 基础命令 3.1 协议/端口过滤 3.2 IP 地址过滤 3.3 高级逻辑组合 3.4 控制输出详细度 3.5 解析包内容 3.6 特殊包过滤 3.7 限制抓包数量 3.8 过滤特定大小包 3.9 过滤提升性能 ​​​​​​3.10 多网卡绑定 3.11 高级…

三高架构杂谈

我们的秒杀请求到了tomcat之后&#xff0c;我整个请求到了后端&#xff0c;我们怎么抗住高并发 也就是让他1s抗住10w的订单量&#xff0c;该怎么做 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>…

后端通用基础代码

后端通用基础代码 通用基础代码是指&#xff1a;“无论在任何后端项目中&#xff0c;都可以复用的代码。这种代码一般 “一辈子只用写一次” &#xff0c;了解作用之后复制粘贴即可&#xff0c;无需记忆。 目录结构如下&#xff1a;1、自定义异常 自定义错误码&#xff0c;对错…

基于51单片机WIFI心率计脉搏体温测量仪APP设计

1 系统功能介绍 本设计基于 STC89C52 单片机&#xff0c;结合 脉搏传感器、温度传感器 DS18B20、LCD1602 液晶显示器、WiFi 模块 等外设&#xff0c;构建了一个 WiFi 心率计脉搏体温测量仪 APP 系统。系统能够实现对人体心率与体温的实时采集、处理、显示和远程上传&#xff0c…

从零到一构建企业级GraphRAG系统:GraphRag.Net深度技术解析

当RAG遇上知识图谱&#xff0c;会碰撞出怎样的火花&#xff1f;本文将带你深入探索GraphRag.Net这个开源项目&#xff0c;看看如何用.NET技术栈打造一个企业级的图谱增强检索系统。 引言&#xff1a;为什么我们需要GraphRAG&#xff1f; 在AI大模型时代&#xff0c;RAG&#x…

前端Element-plus的选择器 el-select 清空内容时,后端对应的更新方式,支持更新为null

1、所属小类选择器 el-select 清空内容时&#xff0c;前端通过事件设置为空字符串clear"handleSmallCategoryClear"【所属小类选择器】只能选择&#xff0c;不能输入信息<script setup lang"ts" name"QualityFileInfoDialog"> ...... // 所…

【笔记】和各大AI大语言模型合作写项目—slirp.go

最近和各大AI大语言模型一起合作写了个小项目&#xff0c;让大家看看AI离取代人类还差多远。 开发大家都在一个共享环境下&#xff0c;连docker都不能运行&#xff0c;rootless也没有。不过好在linux环境&#xff0c;弄个proot能apt或者yum install自由&#xff0c;但是诸如pod…

国标:开展环境卫生满意度调查

随着社会的进步和人们生活水平的提高&#xff0c;&#xff08;满意度调查&#xff09;&#xff08;问卷调查&#xff09;&#xff08;第三方市场咨询公司&#xff09;对生活品质的追求以及对环境保护的重视已经成为了当下社会的主旋律。在这样的背景下&#xff0c;环境卫生问题…

【办公类-54-08】20250902 2025学年第一学期班级点名册模版(双休国定假涂成灰色、修改标题和页眉,批量导出PDF)根据新Excel模版,标题增加园区、空姓名行填充灰色

背景需求: 之前做了优化过的点名册 【办公类-54-07】20250901 2025学年第一学期班级点名册模版(双休国定假涂成灰色、修改标题和页眉,批量导出PDF)-CSDN博客文章浏览阅读984次,点赞27次,收藏29次。【办公类-54-07】20250901 202学年第一学期班级点名册模版(双休国定假…

【C++知识杂记1】智能指针及其分类

智能指针&#xff08;smart pointer&#xff09; 是 C11 引入的一类 模板类&#xff0c;用来封装原始指针&#xff0c;自动管理堆内存的生命周期&#xff0c;避免出现 内存泄漏 和 悬空指针&#xff08;野指针&#xff09; 的问题。 当智能指针对象离开作用域时&#xff0c;它会…

vue从入门到精通:搭建第一个vue项目

目录 Vue是什么 一、nodejs安装 二、安装Vue CLI 三、创建Vue项目 四、配置vue.config.js文件 五、创建第一个应用hello word Vue是什么 Vue是一款‌用于构建用户界面的 JavaScript 渐进式架构‌既可作为库(仅关注视图层)也可扩展为框架,支持从静态页面到复杂单页应用…

C# Queue源码分析

Queue<T> 是 .NET 中实现队列&#xff08;先进先出&#xff09;的一种泛型集合类。它基于数组实现&#xff0c;支持动态扩容、线程不安全&#xff0c;适用于大多数需要队列结构的场景。一、类结构与字段说明 public class Queue<T> : IEnumerable<T>, IColle…

微服务之注册中心与ShardingSphere关于分库分表的那些事

小伙伴们&#xff0c;你们好呀&#xff01;我是老寇&#xff01;跟我一起学习注册中心与ShardingSphere怎么一起使用 使用 nacos-shardingsphere例子&#xff0c;请点击我 注意&#xff1a;需要自己提前创建数据库和表 create database kcloud_platform_test;DROP TABLE IF…

python遇到异常流程

在 Python 中&#xff0c;程序遇到异常时的退出行为取决于是否对异常进行了捕获和处理&#xff1a;未捕获的异常&#xff1a; 如果异常发生后没有被 try-except 语句捕获&#xff0c;程序会立即终止&#xff0c;并返回一个非零的退出码&#xff08;通常是 1&#xff09;&#x…

【开源大模型和闭源大模型分别有哪些?两者的对比?部署私有化模型的必要性有哪些?】

以下是关于开源与闭源大模型的详细对比及私有化部署必要性的分析&#xff0c;结合最新行业动态和技术趋势&#xff1a;一、开源 vs 闭源大模型代表列表 1. 开源大模型&#xff08;2024年主流&#xff09;模型名称参数量机构特点LLaMA-38B-70BMeta商业使用需授权&#xff0c;多语…

SpringBoot--JWT

一、JWT 的简单了解1. 什么是 JWT&#xff1f;JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在 各方之间安全地传输信息。它基于 JSON 格式&#xff0c;信息通过 数字签名 的方式保证不可篡改&#xff0c;常用于 …

OpenTelemetry、Jaeger 与 Zipkin:分布式链路追踪方案对比与实践

OpenTelemetry、Jaeger 与 Zipkin&#xff1a;分布式链路追踪方案对比与实践 问题背景介绍 随着微服务架构的普及&#xff0c;服务之间调用链路变得异常复杂&#xff0c;单一服务故障或性能瓶颈往往牵一发动全身。分布式链路追踪&#xff08;Distributed Tracing&#xff09;能…

云原生俱乐部-RH124知识点总结(1)

RH124内容不是很多&#xff0c;但是也不知道多少能够写完&#xff0c;细节性的东西不会太多&#xff0c;但是确保每个都能够有印象能理解。本来是打算一篇文章写完的&#xff0c;但最后还是决定写一个系列。至于RH124和RH134的内容为什么放在了k8s系列的后面&#xff0c;那只是…