Aurora中的策略模式和模板模式

Aurora中的策略模式和模板模式

在aurora中为了方便以后的扩展使用了策略模式和模板模式实现图片上传和搜索功能,能够在配置类中设置使用Oss或者minio上传图片,es或者mysql文章搜索。后续有新的上传方式或者搜索方式只需要编写对应的实现类即可,其它代码无需更改,做到解耦的效果。

什么是策略模式

策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。

策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)。

  • 环境角色(Context):持有一个策略类的引用,提供给客户端使用。
  • 抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略角色(ConcreteStrategy):包装了相关的算法或行为。

在这里插入图片描述

什么是模板模式

模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

模板模式主要由抽象模板(Abstract Template)角色和具体模板(Concrete Template)角色组成。

  • 抽象模板(Abstract Template): 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤;定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
  • 具体模板(Concrete Template): 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤;每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

https://www.dofactory.com/images/diagrams/net/template.gif

这篇文章把这两个模式讲的很好 https://www.cnblogs.com/xuwujing/p/9954263.html

图片上传

策略模式的应用

图片上传中有两种上传策略Oss和Minio。在上传图片的时候,如果用户配置了Oss那么就选择Oss上传,否则就选择Minio上传。虽然可以用if else判断,但是每次增加新的上传方式就需要在原方法中更改,这样处理会导致难以维护。通过分析我们可以发现Oss和Minio的实现功能都是上传图片,所以我们可以用策略模式把这两个功能的上传功能抽象成一个策略类接口,再分别实现Oss和Minio的上传策略,然后定义环境角色根据配置选择具体的策略上传图片。

模板模式的应用

进一步分析两种上传策略的步骤都是

  1. 根据文件流和配置生成图片在对象存储中的路径
  2. 判断图片是否存在
  3. 不存在则上传图片
  4. 返回图片路径

所以可以定义一个抽象的模板类执行这些步骤,让不同的上传策略实现自己的上传方法和生成路径方法

Tips
  1. 图片上传时,前台传递的参数是一个MultipartFile类型的,调用getInputStream()可以得到图片的输入流,进一步上传给云存储
  2. 环境对象将所有的策略实现类保存在map中,根据yml中配置的上传方式选择对应的策略上传
	@Value("${upload.mode}")private String uploadMode;@Autowired// 每个策略类 都会以 @Service("ossUploadStrategyImpl") 的方式命名,然后被自动注入到map中private Map<String, UploadStrategy> uploadStrategyMap;public String executeUploadStrategy(MultipartFile file, String path) {return uploadStrategyMap.get(getStrategy(uploadMode)).uploadFile(file, path);}

文章搜索

文章搜素中有两种搜索模式 Es 和 Mysql。同样用策略模式将这两中模式的搜索功能抽象成一个接口,分别实现搜索策略,然后定义环境角色根据配置选择具体的策略搜索文章。

需要的搜索功能是:根据输入的单词,在文章的标题和内容中找到相应的位置并高亮显示。

Es搜索逻辑

首先构造搜索条件:

		// 查询条件NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("articleTitle", keywords)).should(QueryBuilders.matchQuery("articleContent", keywords))).must(QueryBuilders.termQuery("isDelete", FALSE)).must(QueryBuilders.termQuery("status", PUBLIC.getStatus()));nativeSearchQueryBuilder.withQuery(boolQueryBuilder);// 高亮显示条件 在关键词前后加上PRE_TAG POST_TAGHighlightBuilder.Field titleField = new HighlightBuilder.Field("articleTitle");titleField.preTags(PRE_TAG);titleField.postTags(POST_TAG);HighlightBuilder.Field contentField = new HighlightBuilder.Field("articleContent");contentField.preTags(PRE_TAG);contentField.postTags(POST_TAG);contentField.fragmentSize(50);nativeSearchQueryBuilder.withHighlightFields(titleField, contentField);

使用elasticsearchRestTemplate根据搜索条件查询

SearchHits<ArticleSearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), ArticleSearchDTO.class);

将结果转为List返回

return search.getSearchHits().stream().map(hit -> {ArticleSearchDTO article = hit.getContent();List<String> titleHighLightList = hit.getHighlightFields().get("articleTitle");if (CollectionUtils.isNotEmpty(titleHighLightList)) {article.setArticleTitle(titleHighLightList.get(0));}List<String> contentHighLightList = hit.getHighlightFields().get("articleContent");if (CollectionUtils.isNotEmpty(contentHighLightList)) {article.setArticleContent(contentHighLightList.get(contentHighLightList.size() - 1));}return article;}).collect(Collectors.toList());
Mysql搜索逻辑

构造搜索条件 && 搜索

List<Article> articles = articleMapper.selectList(new LambdaQueryWrapper<Article>().eq(Article::getIsDelete, FALSE).eq(Article::getStatus, PUBLIC.getStatus()).and(i -> i.like(Article::getArticleTitle, keywords).or().like(Article::getArticleContent, keywords)));

对搜索结果高亮处理截取后返回

return articles.stream().map(item -> {boolean isLowerCase = true;String articleContent = item.getArticleContent();int contentIndex = item.getArticleContent().indexOf(keywords.toLowerCase());if (contentIndex == -1) {contentIndex = item.getArticleContent().indexOf(keywords.toUpperCase());if (contentIndex != -1) {isLowerCase = false;}}if (contentIndex != -1) {int preIndex = contentIndex > 15 ? contentIndex - 15 : 0;String preText = item.getArticleContent().substring(preIndex, contentIndex);int last = contentIndex + keywords.length();int postLength = item.getArticleContent().length() - last;int postIndex = postLength > 35 ? last + 35 : last + postLength;String postText = item.getArticleContent().substring(contentIndex, postIndex);if (isLowerCase) {articleContent = (preText + postText).replaceAll(keywords.toLowerCase(), PRE_TAG + keywords.toLowerCase() + POST_TAG);} else {articleContent = (preText + postText).replaceAll(keywords.toUpperCase(), PRE_TAG + keywords.toUpperCase() + POST_TAG);}} else {return null;}isLowerCase = true;int titleIndex = item.getArticleTitle().indexOf(keywords.toLowerCase());if (titleIndex == -1) {titleIndex = item.getArticleTitle().indexOf(keywords.toUpperCase());if (titleIndex != -1) {isLowerCase = false;}}String articleTitle;if (isLowerCase) {articleTitle = item.getArticleTitle().replaceAll(keywords.toLowerCase(), PRE_TAG + keywords.toLowerCase() + POST_TAG);} else {articleTitle = item.getArticleTitle().replaceAll(keywords.toUpperCase(), PRE_TAG + keywords.toUpperCase() + POST_TAG);}return ArticleSearchDTO.builder().id(item.getId()).articleTitle(articleTitle).articleContent(articleContent).build();}).filter(Objects::nonNull).collect(Collectors.toList());
Tips

Es搜索为什么会比Mysql快呢?

  1. 基于分词后的全文检索,对于模糊搜索Mysql的索引会失效,而es会使用单词字典树结合倒排索引能够快速找到文章位置
  2. 进行精确检索,有些时候可能mysql要快一些,当mysql的非聚合索引引用上了聚合索引,无需回表,则速度上可能更快;es还是通过FST找到倒排索引的位置比获取文档id列表,再根据文档id获取文档并根据相关度进行排序。但是es还有个优势,就是es即天然的分布式能够在大量数据搜索时可以通过分片降低检索规模,并且可以通过并行检索提升效率,用filter时,更是可以直接跳过检索直接走缓存。

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

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

相关文章

在原生html中使用less

引入less <link rel"stylesheet/less" href"./lessDemo.less" /><script src"./js/less.min.js"></script> less.min.js文件下载地址:https://github.com/less/less.js 注意&#xff1a;less文件在前&#xff0c;js文件在后…

深入理解强化学习——强化学习的基础知识

分类目录&#xff1a;《深入理解强化学习》总目录 在机器学习领域&#xff0c;有一类任务和人的选择很相似&#xff0c;即序贯决策&#xff08;Sequential Decision Making&#xff09;任务。决策和预测任务不同&#xff0c;决策往往会带来“后果”&#xff0c;因此决策者需要为…

C++ day2

自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show() #include <ios…

2.4 turtle语法元素分析 | Python语言程序设计(嵩天)

文章目录 课程简介第二章 Python基本图形绘制2.4 turtle语法元素分析2.4.1 库引用与import2.4.2 turtle画笔控制函数2.4.3 turtle运动控制函数2.4.4 turtle方向控制函数2.4.5 循环语句与range()函数&#xff08;基本循环语句&#xff09;2.4.6 "Python蟒蛇绘制"代码分…

软件测试基础 - 测试覆盖率

一、覆盖率概念 覆盖率是用来度量测试完整性的一个手段&#xff0c;是测试技术有效性的一个度量。分为&#xff1a;白盒覆盖、灰盒覆盖和黑盒覆盖&#xff1b;测试用例设计不能一味追求覆盖率&#xff0c;因为测试成本随覆盖率的增加而增加。 覆盖率&#xff08;至少被执行一次…

stm32的时钟、中断的配置(针对寄存器),一些基础知识

一、学习参考资料 &#xff08;1&#xff09;正点原子的寄存器源码。 &#xff08;2&#xff09;STM32F103最小系统板开发指南-寄存器版本_V1.1&#xff08;正点&#xff09; &#xff08;3&#xff09;STM32F103最小系统板开发指南-库函数版本_V1.1&#xff08;正点&#xff0…

C++基础——基础语法

1 注释 C支持单行注释和多行注释。 单行注释 // 注释内容单行注释直到改行末尾&#xff0c;可以与代码放在同一行&#xff0c;在代码后面注释 多行注释 /* 注释内容 */包含在其中的都会被注释 2 变量 变量的作用是给指定的内存空间起名&#xff0c;方便操作这段内存。变…

哈希应用之位图

文章目录 1.位图概念2.面试题引入3.代码解决[配注释]4.位图应用4.1找到100亿个整数里只出现一次的整数4.2找两个分别有100亿个整数的文件的交集[只有1G内存]1.法一[使用于数据量<42亿]2.法二[适用于数据量大>42亿]3.在一个有100亿个int的文件中找到出现次数不超过2次的所…

AI伦理:如何确保人工智能的公平与透明

文章目录 什么是AI伦理&#xff1f;AI公平性AI透明性 为什么AI公平性和透明性重要&#xff1f;确保AI公平性的方法1. 数据收集和准备2. 算法和模型3. 解释和可解释性4. 持续监测 确保AI透明性的方法1. 记录决策2. 可解释性工具3. 用户教育 AI伦理的挑战和未来结论 &#x1f389…

STM32MP157汇编流水灯

.text .global _start _start: /* 使能GPIOE、GPIOF寄存器 RCC_MP_AHB4ENSETR * 基地址: 0x50000000 偏移地址: 0xA28 0x50000A28* RCC_MP_AHB4ENSETR[4]->1 RCC_MP_AHB4ENSETR[5]->1*/ LDR R0,0x50000A28LDR R1,[R0]ORR R1,R1,#(0x1<<4)STR R1,[R0]LDR R0,0x…

C++ 学习系列 -- std::list

一 std::list 介绍 list 是 c 中的序列式容器&#xff0c;其实现是双向链表&#xff0c;每个元素都有两个指针&#xff0c;分别指向前一个节点与后一个节点 链表与数组都是计算机常用的内存数据结构&#xff0c;与数组连续内存空间不一样的地方在于&#xff0c;链表的空间是不…

【Java 进阶篇】HTML块级元素详解

HTML&#xff08;Hypertext Markup Language&#xff09;是用于创建网页的标记语言。在HTML中&#xff0c;元素被分为块级元素和内联元素两种主要类型。块级元素通常用于构建网页的结构&#xff0c;而内联元素则嵌套在块级元素内&#xff0c;用于添加文本和其他内容。本文将重点…

异常:找不到匹配的key exchange算法

目录 问题描述原因分析解决方案 问题描述 PC 操作系统&#xff1a;Windows 10 企业版 LTSC PC 异常软件&#xff1a;XshellPortable 4(Build 0127) PC 正常软件&#xff1a;PuTTY Release 0.74、MobaXterm_Personal_23.1 服务器操作系统&#xff1a;OpenEuler 22.03 (LTS-SP2)…

Ubuntu 22.04 安装系统 手动分区 针对只有一块硬盘 lvm 单独分出/home

自动安装的信息 参考自动安装时产生的分区信息 rootyeqiang-MS-7B23:~# fdisk /dev/sdb -l Disk /dev/sdb&#xff1a;894.25 GiB&#xff0c;960197124096 字节&#xff0c;1875385008 个扇区 Disk model: INTEL SSDSC2KB96 单元&#xff1a;扇区 / 1 * 512 512 字节 扇区大…

phpstudy本地域名伪静态

环境&#xff1a;WNMP(Windows10 Nginx1.15.11 MySQL5.7.26 【PHP 7.4.3 (cli) (built: Feb 18 2020 17:29:57) ( NTS Visual C 2017 x64 ) 】) 使用PhpStudy配置本地域名后&#xff0c;设置伪静态&#xff0c;这样在Web端打开网站就不需要输入index.php了&#xff0c;很简单…

架构方法、模型、范式、治理

从架构方法、模型、范式、治理等四个方面介绍架构的概念和方法论、典型业务场景下的架构范式、不同架构的治理特点这3个方面的内容

Pycharm操作git仓库 合并等

菜单 Git CommitPushUpdate ProjectPullFetchMergreRebase 查询 查询分支 查询本地所有分支 # 查询本地分支 git branch# 查询远程分支 git branch -rPycharm查看当前分支 步骤&#xff1a; Git->Branches 哈喽&#xff0c;大家好&#xff0c;我是[有勇气的牛排]&…

ELK集群 日志中心集群

ES&#xff1a;用来日志存储 Logstash:用来日志的搜集&#xff0c;进行日志格式转换并且传送给别人&#xff08;转发&#xff09; Kibana:主要用于日志的展示和分析 kafka Filebeat:搜集文件数据 es-1 本地解析 vi /etc/hosts scp /etc/hosts es-2:/etc/hosts scp /etc…

视频转GIF:快速生成有趣的动态图片

随着社交媒体的快速发展&#xff0c;GIF动态图片已经成为了人们表达情感、分享生活片段的重要方式。将视频片段转换成GIF动态图片&#xff0c;可以让人们更好地分享和表达自己的情感&#xff0c;也可以让一些有趣的瞬间变得更加生动有趣。本文将介绍如何将视频快速转换成GIF动态…

微信小程序wxs标签 在wxml文件中编写JavaScript逻辑

PC端开发 可以在界面中编写JavaScript脚本 vue/react这些框架更是形成了一种常态 因为模板引擎和jsx语法本身就都是在js中的 我们小程序中其实也有类似的奇妙写法 不过先声明 这东西不是很强大 我们可以先写一个案例代码 wxml代码参考 <view><wxs module"wordSt…