设计模式-适配器模式-注册器模式
设计模式-适配器模式-注册器模式
适配器模式
如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式
适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。
下面这段代码
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 …...

超级灵感:前端页面功能统一管理方案
前端页面功能统一管理方案 引言 我和朋友聊天想到一个灵感,关于支付状态机管理,这个类可以让我们知道具体上一个状态和下一个状态,这是由于那个事件触发改变,这个功能设计非常好! 从而讨论出为什么我们不能把某一个…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...