设计模式-适配器模式-注册器模式
设计模式-适配器模式-注册器模式
适配器模式
如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。
下面这段代码
postService,userService,imageService分别调用的方法逻辑相同参数不同,可使用接口统一调用
@Component
@Slf4j
public class SearchFacade {@Resourceprivate PostService postService;@Resourceprivate UserService userService;@Resourceprivate ImageService imageService;@ResourceThreadPoolTaskExecutor threadPoolTaskExecutor;public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {SearchVo searchVo = new SearchVo();if (searchQueryRequest == null) {return searchVo;}String searchText = searchQueryRequest.getSearchText();String searchType = searchQueryRequest.getSearchType();if (StringUtils.isBlank(searchType)) {CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {PostQueryRequest postQueryRequest = new PostQueryRequest();postQueryRequest.setSearchText(searchText);Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, httpServletRequest);return postVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {UserQueryRequest userQueryRequest = new UserQueryRequest();userQueryRequest.setUserName(searchText);Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);return userVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {ImageQueryRequest imageQueryRequest = new ImageQueryRequest();imageQueryRequest.setSearchText(searchText);Page<Image> imagePage = imageService.getImageByPage(imageQueryRequest);return imagePage;}, threadPoolTaskExecutor);CompletableFuture.allOf(postTask, userTask, imageTask);try {Page<PostVO> postVOPage = postTask.get();searchVo.setPostList(postVOPage.getRecords());Page<UserVO> userVOPage = userTask.get();searchVo.setUserList(userVOPage.getRecords());Page<Image> imagePage = imageTask.get();searchVo.setImageList(imagePage.getRecords());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}} else {SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);switch (searchTypeEnum) {case POST:PostQueryRequest postQueryRequest = new PostQueryRequest();postQueryRequest.setSearchText(searchText);Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, httpServletRequest);searchVo.setPostList(postVOPage.getRecords());break;case USER:UserQueryRequest userQueryRequest = new UserQueryRequest();userQueryRequest.setUserName(searchText);Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);searchVo.setUserList(userVOPage.getRecords());break;case IMAGE:ImageQueryRequest imageQueryRequest = new ImageQueryRequest();imageQueryRequest.setSearchText(searchText);Page<Image> imagePage = imageService.getImageByPage(imageQueryRequest);searchVo.setImageList(imagePage.getRecords());break;default:break;}}return searchVo;}
}
下面实现一个简单的适配器
新建一个数据源接口
/*** @author tuaofei* @description 查询数据源* @date 2024/11/29*/
public interface SearchDataSource<T> {/*** 通用查询接口* @param searchText* @param current* @param pageSize* @return*/Page<T> doSearch(String searchText, int current, int pageSize);
}
postService.listPostVoPage(postQueryRequest, httpServletRequest)
新增PostDataSource数据源
@Service
@Slf4j
public class PostDataSource implements SearchDataSource<PostVO> {@Resourceprivate PostService postService;@Overridepublic Page<PostVO> doSearch(String searchText, int current, int pageSize) {PostQueryRequest postQueryRequest = new PostQueryRequest();postQueryRequest.setSearchText(searchText);postQueryRequest.setCurrent(current);postQueryRequest.setPageSize(pageSize);//HttpServletRequest 这里没法获取,考虑改造接口或改造方法,根据具体情况判断Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, null);return postVOPage;}
}
新增UserDataSource 数据源
userService.listUserVoPage(userQueryRequest)
@Service
@Slf4j
public class UserDataSource implements SearchDataSource<UserVO> {@Resourceprivate UserService userService;@Overridepublic Page<UserVO> doSearch(String searchText, int current, int pageSize) {UserQueryRequest userQueryRequest = new UserQueryRequest();userQueryRequest.setUserName(searchText);Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);return userVOPage;}
}
新增ImageDataSource 数据源
imageService.getImageByPage(imageQueryRequest)
@Service
public class ImageDataSource implements SearchDataSource<Image> {@Resourceprivate ImageService imageService;@Overridepublic Page<Image> doSearch(String searchText, int current, int pageSize) {ImageQueryRequest imageQueryRequest = new ImageQueryRequest();imageQueryRequest.setSearchText(searchText);imageQueryRequest.setCurrent(current);imageQueryRequest.setPageSize(pageSize);Page<Image> imageByPage = imageService.getImageByPage(imageQueryRequest);return imageByPage;}
}
修改SearchFacade里面调用service的逻辑,这样就可以统一调用相同参数的方法,转换逻辑交给具体的数据源
@Component
@Slf4j
public class SearchFacade {@Resourceprivate ImageDataSource imageDataSource;@Resourceprivate PostDataSource postDataSource;@Resourceprivate UserDataSource userDataSource;@Resourceprivate ThreadPoolTaskExecutor threadPoolTaskExecutor;public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {SearchVo searchVo = new SearchVo();if (searchQueryRequest == null) {return searchVo;}String searchText = searchQueryRequest.getSearchText();String searchType = searchQueryRequest.getSearchType();int current = searchQueryRequest.getCurrent();int pageSize = searchQueryRequest.getPageSize();if (StringUtils.isBlank(searchType)) {CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);return postVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);return userVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);return imagePage;}, threadPoolTaskExecutor);CompletableFuture.allOf(postTask, userTask, imageTask);try {Page<PostVO> postVOPage = postTask.get();searchVo.setPostList(postVOPage.getRecords());Page<UserVO> userVOPage = userTask.get();searchVo.setUserList(userVOPage.getRecords());Page<Image> imagePage = imageTask.get();searchVo.setImageList(imagePage.getRecords());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}} else {SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);switch (searchTypeEnum) {case POST:Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);;searchVo.setPostList(postVOPage.getRecords());break;case USER:Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);searchVo.setUserList(userVOPage.getRecords());break;case IMAGE:Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);searchVo.setImageList(imagePage.getRecords());break;default:break;}}return searchVo;}
}
注册器模式
经过上面的修改,我们发现所有的调用查询方法参数都相同,而且都是通过调用实现了SearchDataSource接口的实现类来调用
我们可以简化下面的switch
SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);switch (searchTypeEnum) {case POST:Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);;searchVo.setPostList(postVOPage.getRecords());break;case USER:Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);searchVo.setUserList(userVOPage.getRecords());break;case IMAGE:Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);searchVo.setImageList(imagePage.getRecords());break;default:break;}
需要一个Map<String,SearchDataSource>来注册这些数据源,通过类型来获取对应的数据源,再调用查询方法
@Component
public class DataSourceRegistry {@Resourceprivate ImageDataSource imageDataSource;@Resourceprivate PostDataSource postDataSource;@Resourceprivate UserDataSource userDataSource;private Map<String, SearchDataSource<T>> dataSourceMap;/*** 在依赖注入完成后,执行*/@PostConstructpublic void doInit() {dataSourceMap = new HashMap() {{put(SearchTypeEnum.POST.getValue(), postDataSource);put(SearchTypeEnum.USER.getValue(), userDataSource);put(SearchTypeEnum.IMAGE.getValue(), imageDataSource);}};}public SearchDataSource getDataSourceByType(String searchType) {if (dataSourceMap == null) {return null;}return dataSourceMap.get(searchType);}
}
在SearchFacade使用
@Component
@Slf4j
public class SearchFacade {@Resourceprivate DataSourceRegistry dataSourceRegistry;@Resourceprivate ThreadPoolTaskExecutor threadPoolTaskExecutor;public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {SearchVo searchVo = new SearchVo();if (searchQueryRequest == null) {return searchVo;}String searchText = searchQueryRequest.getSearchText();String searchType = searchQueryRequest.getSearchType();int current = searchQueryRequest.getCurrent();int pageSize = searchQueryRequest.getPageSize();if (StringUtils.isBlank(searchType)) {CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {SearchDataSource postDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.POST.getValue());Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);return postVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {SearchDataSource userDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.USER.getValue());Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);return userVOPage;}, threadPoolTaskExecutor);CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {SearchDataSource imageDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.IMAGE.getValue());Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);return imagePage;}, threadPoolTaskExecutor);CompletableFuture.allOf(postTask, userTask, imageTask);try {Page<PostVO> postVOPage = postTask.get();searchVo.setPostList(postVOPage.getRecords());Page<UserVO> userVOPage = userTask.get();searchVo.setUserList(userVOPage.getRecords());Page<Image> imagePage = imageTask.get();searchVo.setImageList(imagePage.getRecords());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}} else {SearchDataSource<?> dataSource = dataSourceRegistry.getDataSourceByType(searchType);//可以使用公共的返回对象,类型使用泛型Page<?> page = dataSource.doSearch(searchText, current, pageSize);List<?> records = page.getRecords();searchVo.setDataList(records);}return searchVo;}
}
在SearchVo新建公共返回对象
@Data
public class SearchVo implements Serializable {private List<PostVO> postList;private List<Image> imageList;private List<UserVO> userList;/*** 公共返回对象*/private List<?> dataList;
}
相关文章:
设计模式-适配器模式-注册器模式
设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…...
减速机润滑油更换的最佳周期是多久?
减速机是工业设备中的重要组成部分,润滑油的使用对于其正常运转和寿命具有至关重要的作用。那么,减速机多久更换一次润滑油呢?实际上,减速机润滑油的更换周期受多种因素影响,以下是一些具体的更换周期建议:…...
程序执行堆栈执行模拟
所有的文件都是在硬盘(磁盘)上,调用时先调用javac指令的jdk编译成.class然后被java指令的jre送到内存中,java在内存中有自己的一片区域叫JVM,编译进来的文件首先进入方法区。 staitc的属性就是在进入内存的时候开辟了一…...
《Python基础》之数据加密模块hashlib的用法
目录 一、简介 二、用法 步骤一、导入hashlib库 步骤二、创建哈希对象 步骤三、往哈希对象中传值 1、可以在创建对象的时候传值 2、使用updata传值 步骤四、获取经过哈希对象加密后的值 三、注意事项 1、编码问题 2、安全性 3、多次传值 四、总结 一、简介 hashli…...
安装Fcitx5输入框架和输入法自动部署脚本(来自Mark24)-Ubuntu通用
在Ubuntu22.04上安装rime中文输入法的基本教程 上述文章接近废弃。 使用新逻辑配置基本的Fcitx5的输入法。 安装 第一步,下载相关组件 sudo nala install vim sudo nala install ruby sudo nala install fcitx5-rime第二步,设置语言为Fcitx5 而非 默认…...
【IMF靶场渗透】
文章目录 一、基础信息 二、信息收集 三、flag1 四、flag2 五、flag3 六、flag4 七、flag5 八、flag6 一、基础信息 Kali IP:192.168.20.146 靶机IP:192.168.20.147 二、信息收集 Nmap -sP 192.168.20.0/24 Arp-scan -l nmap -sS -sV -p- -…...
Zookeeper选举算法与提案处理概览
共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法,提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为: 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为,如进程崩溃,只要…...
深入了解 Adam 优化器对显存的需求:以 LLaMA-2 7B 模型为例 (中英双语)
中文版 深入了解 Adam 优化器对显存的额外需求:模型参数与优化器状态的显存开销分析 在深度学习模型的训练过程中,显存是一个关键的资源,尤其在处理大型语言模型或深度神经网络时。训练时的显存需求不仅包括模型参数本身,还涉及…...
数据分析学习
数据分析的定义 数据分析是通过对收集到的数据进行清理、转换、建模、分析和解释,从中提取有用的信息和洞察,以帮助做出更好的决策。数据分析可以应用于各种领域,比如商业、金融、医疗、市场营销等,目的是通过数据来发现模式、趋…...
PaddleOCR:一款高性能的OCR工具介绍
一、引言 随着人工智能技术的不断发展,光学字符识别(OCR)技术在各行各业得到了广泛应用。OCR技术能够将图片、扫描件等非结构化数据中的文字信息提取出来,转换为可编辑的文本格式。在我国,百度开源了一款优秀的OCR工具…...
Transformers快速入门代码解析(一):注意力机制——Attention:Scaled Dot-product Attention
Attention:Scaled Dot-product Attention 引言Scaled Dot-product Attention代码 引言 请注意!!!本博客使用了教程Transformers快速入门中的全部代码!!! 只在我个人理解的基础上为代码添加了注释…...
Git中HEAD、工作树和索引的区别
在Git版本控制系统中,HEAD、工作树(Working Tree)和索引(Index)是三个非常重要的概念,它们分别代表了不同的状态或区域,下面我将对这三个概念进行详细的解释。 HEAD 定义:HEAD是一…...
【python量化教程】如何使用必盈API的股票接口,获取最新实时交易数据
实时交易数据简介 股票实时交易数据涵盖股票价格、成交量、涨跌幅等多类信息。其在股票交易中极为关键,高速准确的数据对各方意义重大。投资者可借此及时捕捉机会、优化策略与降低风险;实时准确的实时交易数据是股票市场有效运转的核心要素之一。 使用…...
【C++】动态内存与智能指针——shared_ptr 和 new 结合使用
12.1.3 shared_ptr 和 new 结合使用 如上文所述,如果我们不初始化一个智能指针,那么它将会被初始化为一个空指针(需要注意的是,智能指针与普通指针在此处有着非常明显的区别。如果只声明某个类型的普通指针,而不对它进…...
遥感数据集:FTW全球农田边界和对应影像数据,约160万田块边界及7万多个样本
Fields of The World (FTW) 是一个面向农业田地边界实例分割的基准数据集,旨在推动机器学习模型的发展,满足全球农业监测对高精度、可扩展的田地边界数据的需求。该数据集由kerner-lab提供,于2024年8月28日发布,主要特征包括&…...
马斯克的 AI 游戏工作室:人工智能与游戏产业的融合新纪元
近日,马斯克在 X 平台(前身为 Twitter)发文称,“太多游戏工作室被大型企业所拥有,xAI 将启动一个 AI 游戏工作室,让游戏再次变得精彩”。这一言论不仅展示了马斯克对游戏行业现状的不满,也揭示了…...
URDF(描述机器人模型)和SDF(Gazebo中用于描述仿真环境)
使用URDF(Unified Robot Description Format) URDF是ROS中用于描述机器人模型的XML格式文件。你可以使用XML文件定义机器人的几何形状、惯性参数、关节和链接等。 示例URDF文件(my_robot.urdf): <?xml version&…...
力扣380:O(1)时间插入、删除和获取随机数
实现RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。bool remove(int val) 当元素 val 存在时࿰…...
【C++boost::asio网络编程】有关socket的创建和连接的笔记
socket的创建和连接 tcp客户端创建端点tcp服务端创建端点创建socket创建TCP 服务器端的 acceptor 套接字创建 acceptor 套接字并绑定客户端连接到服务器通过ip地址解析通过域名解析 服务端接收新连接 tcp客户端创建端点 int client_end_point() {std::string raw_ip_address …...
超级灵感:前端页面功能统一管理方案
前端页面功能统一管理方案 引言 我和朋友聊天想到一个灵感,关于支付状态机管理,这个类可以让我们知道具体上一个状态和下一个状态,这是由于那个事件触发改变,这个功能设计非常好! 从而讨论出为什么我们不能把某一个…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
