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

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时,更是可以直接跳过检索直接走缓存。

相关文章:

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

Aurora中的策略模式和模板模式 在aurora中为了方便以后的扩展使用了策略模式和模板模式实现图片上传和搜索功能&#xff0c;能够在配置类中设置使用Oss或者minio上传图片&#xff0c;es或者mysql文章搜索。后续有新的上传方式或者搜索方式只需要编写对应的实现类即可&#xff…...

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 字节 扇区大…...

Android系统定制之监听USB键盘来判断是否弹出软键盘

一.项目背景 在设备上弹出软键盘,会将一大部分UI遮挡起来,造成很多图标无法看到和点击,使用起来不方便,因此通过插入usb键盘输入代替软键盘,但是点击输入框默认会弹出软键盘,因此想要插入USB键盘时,默认关闭软键盘,拔出键盘时再弹出,方便用户使用 二.设计思路 2.1…...

LeakyReLU激活函数

nn.LeakyReLU 是PyTorch中的Leaky Rectified Linear Unit&#xff08;ReLU&#xff09;激活函数的实现。Leaky ReLU是一种修正线性单元&#xff0c;它在非负数部分保持线性&#xff0c;而在负数部分引入一个小的斜率&#xff08;通常是一个小的正数&#xff09;&#xff0c;以防…...

Qt单一应用实例判断

原本项目中使用QSharedMemory的方法来判断当前是否已存在运行的实例&#xff0c;但在MacOS上&#xff0c;当程序异常崩溃后&#xff0c;QSharedMemory没有被正常销毁&#xff0c;导致应用程序无法再次被打开。 对此&#xff0c;Qt assistant中有相关说明&#xff1a; 摘抄 qt-s…...

企业AI工程化之路:如何实现高效、低成本、高质量的落地?

MLOps工程实践 概述面临挑战目的内容简介读者对象专家推荐目录 写在末尾&#xff1a; 主页传送门&#xff1a;&#x1f4c0; 传送 概述 作为计算机科学的一个重要领域&#xff0c;机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#x…...

最短路径专题8 交通枢纽 (Floyd求最短路 )

题目&#xff1a; 样例&#xff1a; 输入 4 5 2 0 1 1 0 2 5 0 3 3 1 2 2 2 3 4 0 2 输出 0 7 思路&#xff1a; 由题意&#xff0c;绘制了该城市的地图之后&#xff0c;由给出的 k 个编号作为起点&#xff0c;求该点到各个点之间的最短距离之和最小的点是哪个&#xff0c;并…...

文件扫描模块

文章目录 前言文件扫描模块设计初级扫描方案一实现单线程扫描整合扫描步骤 设计初级扫描方案二周期性扫描 总结 前言 我们这个模块考虑的是数据库里面的内容从哪里获取。 获取完成后&#xff0c;这时候,我们就需要把目录里面文件/子文件都获取出来,并存入数据库。 文件扫描模…...

MySQL之主从复制

概述&#xff1a; 将主库的数据 变更同步到从库&#xff0c;从而保证主库和从库数据一致。 它的作用是 数据备份&#xff0c;失败迁移&#xff0c;读写分离&#xff0c;降低单库读写压力 原理&#xff1a; 主服务器上面的任何修改都会保存在二进制日志&#xff08; Bin-log日志…...

[leetcode 单调栈] 901. 股票价格跨度 M

设计一个算法收集某些股票的每日报价&#xff0c;并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数&#xff08;从今天开始往回数&#xff0c;包括今天&#xff09;。 例如&#xff0c;如果未来 7 天股票的价格是 [100…...

Java线程池:并发编程的利器

Java线程池&#xff1a;并发编程的利器 在多任务、高并发的时代&#xff0c;Java并发编程显得尤为重要。其中&#xff0c;Java线程池是一种高效的管理线程的工具&#xff0c;能够提高应用程序的性能和响应速度。本文将深入探讨Java线程池的工作原理、应用场景以及简单示例&…...

ARM硬件断点

hw_breakpoint 是由处理器提供专门断点寄存器来保存一个地址&#xff0c;是需要处理器支持的。处理器在执行过程中会不断去匹配&#xff0c;当匹配上后则会产生中断。 内核自带了硬件断点的样例linux-3.16\samples\hw_breakpoint\data_breakpoint.c static void sample_hbp_h…...

Java使用WebSocket(基础)

准备一个html页面 <!DOCTYPE HTML> <html> <head><meta charset"UTF-8"><title>WebSocket Demo</title> </head> <body><input id"text" type"text" /><button onclick"send()&…...

图像处理与计算机视觉--第五章-图像分割-自适应阈值分割

文章目录 1.自适应阈值分割介绍2.自适应阈值函数参数解析3.高斯概率函数介绍4.自适应阈值分割核心代码5.自适应阈值分割效果展示6.参考文章及致谢 1.自适应阈值分割介绍 在图片处理过程中&#xff0c;针对铺前进行二值化等操作的时候&#xff0c;我们希望能够将图片相应区域内所…...

记一次问题排查

1785年&#xff0c;卡文迪许在实验中发现&#xff0c;把不含水蒸气、二氧化碳的空气除去氧气和氮气后&#xff0c;仍有很少量的残余气体存在。这种现象在当时并没有引起化学家的重视。 一百多年后&#xff0c;英国物理学家瑞利测定氮气的密度时&#xff0c;发现从空气里分离出来…...

【Spring Boot】创建一个 Spring Boot 项目

创建一个 Spring Boot 项目 1. 安装插件2. 创建 Spring Boot 项目3. 项目目录介绍和运行注意事项 1. 安装插件 IDEA 中安装 Spring Boot Helper / Spring Assistant / Spring Initializr and Assistant插件才能创建 Spring Boot 项⽬ &#xff08;有时候不用安装&#xff0c;直…...

flutter中使用缓存

前言 在flutter项目中使用ListView或者PageView等有滚动条组件的时候&#xff0c;切换页面的时候&#xff0c;再切换回来会丢失之前的滑动状态&#xff0c;这个时候就需要需要使用缓存功能 缓存类 import package:flutter/material.dart;class KeepAliveWrapper extends Sta…...

京东数据分析平台:9月中上旬白酒消费市场数据分析

9月份&#xff0c;围绕白酒的热点不断。9月5日&#xff0c;瑞幸咖啡官微发布消息称&#xff0c;瑞幸与贵州茅台跨界合作推出的酱香拿铁刷新单品纪录&#xff0c;首日销量突破542万杯&#xff0c;销售额破1亿元。9月14日&#xff0c;贵州茅台官微发布消息称与德芙推出联名产品“…...

Linux安装 spark 教程详解

目录 一 准备安装包 二 安装 scala 三 修改配置文件 1&#xff09;修改 workers 文件 2&#xff09;修改 spark-env.sh文件 四 进入 spark 交互式平台 一 准备安装包 可以自行去 spark 官网下载想要的版本 这里准备了 spark3.1.2的网盘资源 链接: https://pan.baidu.com…...

动态内存管理函数(malloc,calloc,realloc,free)

动态内存函数 1.1malloc和free C语言提供了一个动态内存开辟的函数&#xff1a; void* malloc (size_t size); 这个函数向内存申请一块连续可用的空间&#xff0c;并返回指向这块空间的指针。 如果开辟成功&#xff0c;则返回一个指向开辟好空间的指针。如果开辟失败&#…...

云表|都有生产管理模块,MES和ERP有什么不同,该如何选择

MES和ERP是生产制造领域的两大知名系统&#xff0c;虽然早已声名鹊起&#xff0c;但仍有不少人难以明确区分两者的差异。下面将详细阐述这两个系统的不同之处。首先&#xff0c;要了解MES和ERP的定义。 MES系统&#xff1a;全称制造执行系统&#xff08;Manufacturing Executio…...

C语言 - 数组

目录 1. 一维数组的创建和初始化 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3. 数组越界 4. 数组作为函数参数 4.1…...

Vue 中的插槽(Slot),有什么用,不同插槽的区别?

Vue 中的插槽&#xff08;Slot案例详解&#xff09; 是一种非常有用的功能&#xff0c;用于组件之间的内容分发和复用。以下是关于插槽的一些重要概念&#xff1a; 插槽的作用: 插槽允许你将组件的内容分发到其子组件中&#xff0c;以实现灵活的组件复用和自定义布局。通过插槽…...

Linux登录自动执行脚本

一、所有用户每次登录时自动执行。 1、在/etc/profile文件末尾添加。 将启动命令添加到/etc/profile文件末尾。 2、在/etc/profile.d/目录下添加sh脚本。 在/etc/profile.d/目录下新建sh脚本&#xff0c;设置每次登录自动执行脚本。有用户登录时&#xff0c;/etc/profile会遍…...

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

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

Linux 安全 - 内核提权

文章目录 前言一、简介1.1 prepare_creds1.2 commit_creds 二、demo参考资料 前言 在这篇文章&#xff1a;Linux 安全 - Credentials 介绍了 Task Credentials 相关的知识点&#xff0c;接下来给出一个内核编程提权的例程。 一、简介 内核模块提权主要借助于 prepare_creds …...

数字三角形加强版题解(组合计数+快速幂+逆元)

Description 一个无限行的数字三角形&#xff0c;第 i 行有 i 个数。第一行的第一个数是 1 &#xff0c;其他的数满足如下关系&#xff1a;如果用 F[i][j] 表示第 i 行的第 j 个数&#xff0c;那么 F[i][j]A∗F[i−1][j]B∗F[i−1][j−1] &#xff08;不合法的下标的数为 0 &a…...

MySQL:主从复制-基础复制(6)

环境 主服务器 192.168.254.1 从服务器&#xff08;1&#xff09;192.168.254.2 从服务器&#xff08;2&#xff09;192.168.253.3 我在主服务器上执行的操作会同步至从服务器 主服务器 yum -y install ntp 我们去配置ntp是需要让从服务器和我们主服务器时间同步 sed -i /…...

盒子模型的基础

盒子模型 边框&#xff08;border&#xff09; border可以设置元素的边框&#xff0c;边框分成三部分&#xff0c;边框的&#xff08;粗细&#xff09;边框的样式&#xff0c;边框的颜色 <style>div {width: 100px;height: 100px;border-width: 200;border-style: 边框…...

Go复合类型之数组类型

Go复合类型之数组 文章目录 Go复合类型之数组一、数组(Array)介绍1.1 基本介绍1.2 数组的特点 二、数组的声明与初始化2.1 数组声明2.2 常见的数据类型声明方法2.3 数组的初始化方式一&#xff1a;使用初始值列表初始化数组方法二&#xff1a;根据初始值个数自动推断数组长度方…...

大型的营销型网站建设/旧版优化大师

题目描述&#xff1a; 数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中&#xff0c;第5位&#xff08;从0开始计数&#xff09;是5&#xff0c;第13位是1&#xff0c;第19位是4&#xff0c;等等。请写一个函数&#xff0c;求任意第n位对应的数字。…...

做第三方团购的平台网站/seo实战培训费用

编码规范 1. 缩进 采用2个空格缩进&#xff0c;而不是tab缩进。空格在编辑器中与字符是等宽的&#xff0c;而tab可能因编辑器的设置不同。2个空格会让代码看起来紧凑、明快。 2. 变量声明 永远用var声明变量&#xff0c;不加var时会将其变为全局变量&#xff0c;这样可能会意外…...

跨境网站建设/搜索引擎付费推广

春节将至&#xff0c;这一年终于磕磕绊绊地过来了。借此机会&#xff0c;分享一首诗歌作品&#xff0c;与君共勉&#xff01; 过去的一年&#xff0c;有收获、有失落、有悲伤、有喜悦&#xff0c;五味杂陈&#xff0c;正是人生的本来滋味。新的一年里&#xff0c;希望可以多发论…...

mobile wordpress.org/社区推广

ubuntu12.04&#xff08;32位&#xff09;下TQ2440开发板环境搭建 Step 1.安装arm-linux-gcc交叉编译器 这里我使用的是天嵌tq2440光盘下的EABI-4.3.3_EmbedSky_20100610.tar.bz2安装包。 1、在根目录下解压EABI-4.3.3_EmbedSky_20100610.tar.bz2sudo tar -xvfEABI-4.3.3_Embe…...

做花茶网站解说/百度指数分析平台

条码打印软件是一款应用广泛、功能灵活、操作简单的标签设计软件。软件工具箱中有很多功能按钮&#xff0c;使其能够在很短的时间内根据自己的需求在软件中设计出符合自己需要的标签。那么&#xff0c;在条码打印软件中该如何绘制圆角矩形呢&#xff1f;下面就给大家演示下绘制…...

国外专门做旅游攻略的网站/广州疫情最新消息今天封城了

6月29日&#xff0c;MWC2017大会在上海新国际博览中心拉开帷幕。本届MWC以“势在人为”为主题&#xff0c;邀请了多位来自全球顶尖的通信、运营商、终端等企业的重量级嘉宾进行主题演讲&#xff0c;就物联网、增强现实与虚拟现实等最新行业趋势展开了深入探讨。在智能革命加速到…...