【java實現一個接口多個實現類通用策略模式】

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;那只是…