当前位置: 首页 > news >正文

设计模式-适配器模式-注册器模式

设计模式-适配器模式-注册器模式

适配器模式

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

image-20241129230331103

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

下面这段代码

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;
}

相关文章:

设计模式-适配器模式-注册器模式

设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台&#xff0c;需要适配或接入不同的数据源&#xff0c;可能提供的方法参数和平台调用的方法参数不一致&#xff0c;可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…...

减速机润滑油更换的最佳周期是多久?

减速机是工业设备中的重要组成部分&#xff0c;润滑油的使用对于其正常运转和寿命具有至关重要的作用。那么&#xff0c;减速机多久更换一次润滑油呢&#xff1f;实际上&#xff0c;减速机润滑油的更换周期受多种因素影响&#xff0c;以下是一些具体的更换周期建议&#xff1a;…...

程序执行堆栈执行模拟

所有的文件都是在硬盘&#xff08;磁盘&#xff09;上&#xff0c;调用时先调用javac指令的jdk编译成.class然后被java指令的jre送到内存中&#xff0c;java在内存中有自己的一片区域叫JVM&#xff0c;编译进来的文件首先进入方法区。 staitc的属性就是在进入内存的时候开辟了一…...

《Python基础》之数据加密模块hashlib的用法

目录 一、简介 二、用法 步骤一、导入hashlib库 步骤二、创建哈希对象 步骤三、往哈希对象中传值 1、可以在创建对象的时候传值 2、使用updata传值 步骤四、获取经过哈希对象加密后的值 三、注意事项 1、编码问题 2、安全性 3、多次传值 四、总结 一、简介 hashli…...

安装Fcitx5输入框架和输入法自动部署脚本(来自Mark24)-Ubuntu通用

在Ubuntu22.04上安装rime中文输入法的基本教程 上述文章接近废弃。 使用新逻辑配置基本的Fcitx5的输入法。 安装 第一步&#xff0c;下载相关组件 sudo nala install vim sudo nala install ruby sudo nala install fcitx5-rime第二步&#xff0c;设置语言为Fcitx5 而非 默认…...

【IMF靶场渗透】

文章目录 一、基础信息 二、信息收集 三、flag1 四、flag2 五、flag3 六、flag4 七、flag5 八、flag6 一、基础信息 Kali IP&#xff1a;192.168.20.146 靶机IP&#xff1a;192.168.20.147 二、信息收集 Nmap -sP 192.168.20.0/24 Arp-scan -l nmap -sS -sV -p- -…...

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法&#xff0c;提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为&#xff1a; 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为&#xff0c;如进程崩溃&#xff0c;只要…...

深入了解 Adam 优化器对显存的需求:以 LLaMA-2 7B 模型为例 (中英双语)

中文版 深入了解 Adam 优化器对显存的额外需求&#xff1a;模型参数与优化器状态的显存开销分析 在深度学习模型的训练过程中&#xff0c;显存是一个关键的资源&#xff0c;尤其在处理大型语言模型或深度神经网络时。训练时的显存需求不仅包括模型参数本身&#xff0c;还涉及…...

数据分析学习

数据分析的定义 数据分析是通过对收集到的数据进行清理、转换、建模、分析和解释&#xff0c;从中提取有用的信息和洞察&#xff0c;以帮助做出更好的决策。数据分析可以应用于各种领域&#xff0c;比如商业、金融、医疗、市场营销等&#xff0c;目的是通过数据来发现模式、趋…...

PaddleOCR:一款高性能的OCR工具介绍

一、引言 随着人工智能技术的不断发展&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术在各行各业得到了广泛应用。OCR技术能够将图片、扫描件等非结构化数据中的文字信息提取出来&#xff0c;转换为可编辑的文本格式。在我国&#xff0c;百度开源了一款优秀的OCR工具…...

Transformers快速入门代码解析(一):注意力机制——Attention:Scaled Dot-product Attention

Attention&#xff1a;Scaled Dot-product Attention 引言Scaled Dot-product Attention代码 引言 请注意&#xff01;&#xff01;&#xff01;本博客使用了教程Transformers快速入门中的全部代码&#xff01;&#xff01;&#xff01; 只在我个人理解的基础上为代码添加了注释…...

Git中HEAD、工作树和索引的区别

在Git版本控制系统中&#xff0c;HEAD、工作树&#xff08;Working Tree&#xff09;和索引&#xff08;Index&#xff09;是三个非常重要的概念&#xff0c;它们分别代表了不同的状态或区域&#xff0c;下面我将对这三个概念进行详细的解释。 HEAD 定义&#xff1a;HEAD是一…...

【python量化教程】如何使用必盈API的股票接口,获取最新实时交易数据

实时交易数据简介 股票实时交易数据涵盖股票价格、成交量、涨跌幅等多类信息。其在股票交易中极为关键&#xff0c;高速准确的数据对各方意义重大。投资者可借此及时捕捉机会、优化策略与降低风险&#xff1b;实时准确的实时交易数据是股票市场有效运转的核心要素之一。 使用…...

【C++】动态内存与智能指针——shared_ptr 和 new 结合使用

12.1.3 shared_ptr 和 new 结合使用 如上文所述&#xff0c;如果我们不初始化一个智能指针&#xff0c;那么它将会被初始化为一个空指针&#xff08;需要注意的是&#xff0c;智能指针与普通指针在此处有着非常明显的区别。如果只声明某个类型的普通指针&#xff0c;而不对它进…...

遥感数据集:FTW全球农田边界和对应影像数据,约160万田块边界及7万多个样本

Fields of The World (FTW) 是一个面向农业田地边界实例分割的基准数据集&#xff0c;旨在推动机器学习模型的发展&#xff0c;满足全球农业监测对高精度、可扩展的田地边界数据的需求。该数据集由kerner-lab提供&#xff0c;于2024年8月28日发布&#xff0c;主要特征包括&…...

马斯克的 AI 游戏工作室:人工智能与游戏产业的融合新纪元

近日&#xff0c;马斯克在 X 平台&#xff08;前身为 Twitter&#xff09;发文称&#xff0c;“太多游戏工作室被大型企业所拥有&#xff0c;xAI 将启动一个 AI 游戏工作室&#xff0c;让游戏再次变得精彩”。这一言论不仅展示了马斯克对游戏行业现状的不满&#xff0c;也揭示了…...

URDF(描述机器人模型)和SDF(Gazebo中用于描述仿真环境)

使用URDF&#xff08;Unified Robot Description Format&#xff09; URDF是ROS中用于描述机器人模型的XML格式文件。你可以使用XML文件定义机器人的几何形状、惯性参数、关节和链接等。 示例URDF文件&#xff08;my_robot.urdf&#xff09;&#xff1a; <?xml version&…...

力扣380:O(1)时间插入、删除和获取随机数

实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回 false 。bool remove(int val) 当元素 val 存在时&#xff0…...

【C++boost::asio网络编程】有关socket的创建和连接的笔记

socket的创建和连接 tcp客户端创建端点tcp服务端创建端点创建socket创建TCP 服务器端的 acceptor 套接字创建 acceptor 套接字并绑定客户端连接到服务器通过ip地址解析通过域名解析 服务端接收新连接 tcp客户端创建端点 int client_end_point() {std::string raw_ip_address …...

超级灵感:前端页面功能统一管理方案

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

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

xmind转换为markdown

文章目录 解锁思维导图新姿势&#xff1a;将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件&#xff08;ZIP处理&#xff09;2.解析JSON数据结构3&#xff1a;递归转换树形结构4&#xff1a;Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析

目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork&#xff08;创建个人副本&#xff09;步骤 2: Clone&#xff08;克隆…...