【原创实现 设计模式】Spring+策略+模版+工厂模式去掉if-else,实现开闭原则,优雅扩展

1 定义与优点

1.1 定义

策略模式(Strategy Pattern)属于对象的⾏为模式。他主要是用于针对同一个抽象行为,在程序运行时根据客户端不同的参数或者上下文,动态的选择不同的具体实现方式,即类的行为可以在运行时更改。
策略模式定义了一系列算法或实现策略,并将每个算法封装在独立的类中,所以对一个策略行为进行修改、添加或者删除策略时不会影响到原有的策略,也就是开闭原则的具体表现。

1.2 优势

  • 方便扩展:使用策略模式可以方便的添加、删除、替换策略,只需要增加策略类即可,不需要修改原有代码
  • 可读性好:不通的策略实现分布在不通的实现类中互不依赖,结构清晰,易于理解。
  • 避免大量的条件判断:使用传统的if-else在分支过多时难以维护,并且不符合开闭原则,增加策略类型时需要增加if-else代码,使用策略模式即可避免这一点。

2 场景与目标

假如你的项目对于文件上传这个业务支持多种具体实现,不仅支持AWS S3、腾讯云 COS、阿里云 OSS,后续还可能接入华为云、Oracle云等云厂商的对象存储。每个待上传的文件都有一个需要上传到哪个对象存储类型的属性,那么对于文件上传有以下的处理步骤:

  • 根据待上传文件信息选择选择不通的对象存储的上传客户端
  • 一些公共的逻辑,比如参数校验,日志记录
    在这里插入图片描述

3 实现

可以使用策略模式+模版方法+工厂模式,并在Spring中进行应用实现。

  • 定义一个文件上传的策略接口
  • 定义一个抽象类实现这个接口,并实现不同对象存储的通用逻辑,定义子类的模版方法
  • 具体不同的对象存储客户端实现抽象类,并实现抽象方法并且定义为一个bean
  • 定义一个工厂管理具体的实现类对象
  • 客户端使用工厂类来获取不同对象存储的具体实现类

具体实现如下:

  1. 定义文件上传的策略接口
public interface CloudStorage {/*** 上传文件** @param uploadPath 上传文件到哪个目录下* @param localFile 待上传的文件*/void upload(String uploadPath, File localFile);}
  1. 定义一个公共的抽象类,所有对象存储都会用到的通用处理逻辑放在这里,然后定义一个doUpload()方法让子类来实现,也即模版方法的具体体现
@Slf4j
public abstract class AbstractCloudStorage implements CloudStorage {/*** 上传文件** @param uploadPath 上传文件到哪个目录下* @param localFile  待上传的文件*/@Overridepublic void upload(String uploadPath, File localFile) {if (StringUtils.isBlank(uploadPath) || Objects.isNull(localFile) || !localFile.exists()) {log.warn("参数异常, uploadPath={}, localFile={}", uploadPath, localFile.getPath());return;}long start = System.currentTimeMillis();doUpload(uploadPath, localFile);log.info("上传完成,耗时:{}ms", (System.currentTimeMillis() - start));}/*** 上传文件** @param uploadPath 上传文件到哪个目录下* @param localFile  待上传的文件*/public abstract void doUpload(String uploadPath, File localFile);
}
  1. 定义不同策略的实现类,增加一种策略只需要增加一个类即可,以达到开放封闭的目的
@Slf4j
@Component
public class CosClient extends AbstractCloudStorage {/*** 上传文件** @param uploadPath 上传文件到哪个目录下* @param localFile 待上传的文件*/@Overridepublic void doUpload(String uploadPath, File localFile) {log.info("Tencent COS 上传文件");}
}@Slf4j
@Component
public class S3Client extends AbstractCloudStorage {/*** 上传文件** @param uploadPath 上传文件到哪个目录下* @param localFile 待上传的文件*/@Overridepublic void doUpload(String uploadPath, File localFile) {log.info("AWS S3 上传文件");}
}
  1. 最后定义一个工厂类,来获取不同类型的对象存储策略的文件上传实例
@Slf4j
@Component
public class CloudStorageClientFactory {@Autowiredprivate Map<String, CloudStorage> cloudStorageMap;/*** 通过对象存储类型获取实际客户端** @param storageType 对象存储类型* @return 对象存储客户端*/public CloudStorage getByType(String storageType) {return cloudStorageMap.get(storageType);}
}

4 客户端调用

通过上面的对策略模式的定义和实现,接下来创建一个上传文件的服务来处理文件上传请求

@Slf4j
@Component
public class FileUploadService {@Autowiredprivate CloudStorageClientFactory cloudStorageClientFactory;/*** 文件上传*/public void fileUpload(FileInfo fileInfo) {// 通过文件需要上传的存储类型获取对应的客户端CloudStorage cloudStorage = cloudStorageClientFactory.getByType(fileInfo.getStorageType());// 执行客户端的文件上传cloudStorage.upload(fileInfo.getUploadPath(), fileInfo.getFile());}
}

通过以上的实现,使用了工厂模式来创建不同类型的对象存储客户端实例,使用策略模式来处理文件上传请求来避免了if-else条件判断,代码简洁易于维护和扩展。
使用模版方法处理了上传文件的公共逻辑,实现了代码优雅复用。这样的实现方式在项目中的实际使用非常频繁。

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

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

相关文章

WIN32核心编程 - 数据类型 错误处理 字符处理

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 数据类型 基本数据类型 Win32基本数据类型 错误处理 C语言中的错误处理 C中的错误处理 Win32中的错误处理 字符处理 C/C WIN32 字符处理 数据类型 基本数据类型 C/C语言定义了一系列…

双指针系列第 8 篇:盛水最多的容器。几句话讲明白!

Leetcode 题目链接 思路 取首尾双指针和水量如下所示&#xff0c;设高度函数为 h ( i ) h(i) h(i)&#xff0c;在下图中 h ( l ) < h ( r ) h(l) < h(r) h(l)<h(r)。 观察以 l l l 为左边界所能构成的其他水量&#xff0c;与矮的右边界搭配结果如下。 与高的…

Vue移动端地图App:van-uploader导致的卡顿问题

问题描述 基于Vue3+Vant IU 4开发的移动端地图App,在进行地图点位上报、上报记录查看过程中,出现App卡顿、甚至闪退的问题,进行问题定位之后,发现是van-uploader组件导致的问题。 van-uploader文件上传组件 van-uploader组件用于将本地的图片或文件上传至服务器,并在上传…

GOROOT GOPATH GOPROXY GO111MODULE

GOROOT GOROOT代表Go的安装目录。可执行程序go(或go.exe)和gofmt(或gofmt.exe)位于 GOROOT/bin目录中。 配置GOROOT环境变量&#xff0c;其值为Go的安装目录&#xff1b;然后在环境变量PATH中添加GOROOT/bin路径。 注意&#xff1a;GOROOT变量只是代表了安装目录&#xff0c;不…

Python基础小知识问答系列-可迭代型变量赋值

1. 问题&#xff1a; 怎样简洁的把列表中的元素赋值给单个变量&#xff1f; 当需要列表中指定几个值时&#xff0c;剩余的变量都收集在一起&#xff0c;该怎么进行变量赋值&#xff1f; 当只需要列表中指定某几个值&#xff0c;其他值都忽略时&#xff0c;该怎么…

红酒与建筑:品味历史与艺术的交汇

在时间的长河中&#xff0c;红酒与建筑都是人类智慧的结晶&#xff0c;它们各自承载着历史的厚重与艺术的韵味。当这两者交汇时&#xff0c;仿佛是一场穿越时空的对话&#xff0c;将我们带入一个既古老又现代、既深沉又温柔的世界。今天&#xff0c;就让我们一起走进这个奇妙的…

【前端VUE】VUE3第一节—vite创建vue3工程

什么是VUE Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0…

网页计算器的实现

简介 该项目实现了一个功能完备、交互友好的网页计算器应用。只使用了 HTML、CSS 和 JavaScript &#xff0c;用于检验web前端基础水平。 开发环境&#xff1a;Visual Studio Code开发工具&#xff1a;HTML5、CSS3、JavaScript实现效果 功能设计和模块划分 显示模块&#…

[数据集][目标检测]围栏破损检测数据集VOC+YOLO格式1196张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1196 标注数量(xml文件个数)&#xff1a;1196 标注数量(txt文件个数)&#xff1a;1196 标注…

1、音视频解封装流程---解复用

对于一个视频文件(mp4格式/flv格式)&#xff0c;audio_pkt或者video_pkt是其最基本的数据单元&#xff0c;即视频文件是由独立的视频编码包或者音频编码包组成的。 解复用就是从视频文件中把视频包/音频包单独读取出来保存成独立文件&#xff0c;那么如何得知packet是视频包还是…

MySQL高级-SQL优化- count 优化 - 尽量使用count(*)

文章目录 1、count 优化2、count的几种用法3、count(*)4、count(id)5、count(profession)6、count(null)7、 count(1) 1、count 优化 MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count&#xff08;*&#xff09;的时候会直接返回这个数&#xff0c;效率很高&a…

esp12实现的网络时钟校准

网络时间的获取是通过向第三方服务器发送GET请求获取并解析出来的。 在本篇博客中&#xff0c;网络时间的获取是一种自动的行为&#xff0c;当系统成功连接WiFi获取到网络天气后&#xff0c;系统将自动获取并解析得到时间和日期&#xff0c;为了减少误差每两分钟左右进行一次校…

代码随想录-Day46

121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…

『MySQL 实战 45 讲』22 - MySQL 有哪些“饮鸩止渴”提高性能的方法?

MySQL 有哪些“饮鸩止渴”提高性能的方法&#xff1f; 需求&#xff1a;业务高峰期&#xff0c;生产环境的 MySQL 压力太大&#xff0c;没法正常响应&#xff0c;需要短期内、临时性地提升一些性能 短连接风暴 短连接模式&#xff1a;执行很少的 SQL 语句就断开&#xff0c;…

使用NFS网关功能将HDFS挂载到本地系统

HDFS安装教程 HDFS安装教程http://t.csdnimg.cn/2ziFd 使用NFS网关功能将HDFS挂载到本地系统 简介 HDFS提供了基于NFS&#xff08;Network File System&#xff09;的插件&#xff0c;可以对外提供NFS网关&#xff0c;供其它系统挂载使用。 NFS 网关支持 NFSv3&#xff0c;并…

接口测试流程及测试点!

一、什么时候开展接口测试 1.项目处于开发阶段&#xff0c;前后端联调接口是否请求的通&#xff1f;&#xff08;对应数据库增删改查&#xff09;--开发自测 2.有接口需求文档&#xff0c;开发已完成联调&#xff08;可以转测&#xff09;&#xff0c;功能测试展开之前 3.专…

使用 Ollama 时遇到的问题

题意&#xff1a; ImportError: cannot import name Ollama from llama_index.llms (unknown location) - installing dependencies does not solve the problem Python 无法从 llama_index.llms 模块中导入名为 Ollama 的类或函数 问题背景&#xff1a; I want to learn LL…

vscode中的字符缩进问题

问题描述&#xff1a; 如图当一行代码中出现不同类型的字符时&#xff0c;使用tab缩只是插入了固定数量&#xff08;默认4&#xff09;的空格或制表符&#xff0c;仍然无法对齐。 解决方法&#xff1a; vscode找到设置&#xff0c;搜索fontFamily&#xff0c;对应输入框写入mon…

Git 基础-创建版本库 git init、添加到暂存区git add、查看状态git status、查看改动git diff

目录 1.创建版本库 git init 1.创建版本库 git init 在目录中创建新的 Git 仓库。 你可以在任何时候、任何目录中这么做&#xff0c;完全是本地化的。 在目录中执行 git init&#xff0c;就可以创建一个 Git 仓库了。 注意: 没事不要手动修改 .git 目录里面的文件&#xff0c;不…

Leetcode[反转链表]

LCR 024. 反转链表 给定单链表的头节点 head &#xff0c;请反转链表&#xff0c;并返回反转后的链表的头节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示…