2296 字
约 7 分钟
29
策略模式 + 工厂模式:让文件上传支持多种存储方案

策略模式 + 工厂模式:让文件上传支持多种存储方案

在对象存储业务中,文件上传看起来只是一个简单功能:

上传文件

但真正落地时,文件可能存储到:

Minio
阿里云 OSS
七牛云
腾讯云 COS
华为云 OBS

这些存储产品完成的事情都是一样的:

上传文件。

但是底层 SDK、配置、上传逻辑却完全不同。

如果把所有逻辑都写到一个 Service 中,随着存储平台越来越多,代码会越来越难维护。

这时候就非常适合使用:

策略模式 + 工厂模式

教程中的业务背景也是如此:当前计划支持 Minio 和阿里云 OSS,同时考虑未来可能继续引入其他对象存储,因此需要提前考虑代码的扩展性。


一、如果不用设计模式,会有什么问题?

最简单的做法可能是:

如果 storage.type = minio
    执行 Minio 上传

否则如果 storage.type = aliyun
    执行阿里云上传

一开始只有两个平台,看起来没什么问题。

但是后面可能变成:

if minio

else if aliyun

else if qiniu

else if tencent

else if huawei

最终一个文件上传 Service 中会同时存在:

Minio 上传逻辑
阿里云 OSS 上传逻辑
七牛云上传逻辑
腾讯云上传逻辑
华为云上传逻辑

这时候 Service 的职责就太多了。

而且以后增加新的存储平台,还要继续修改原来的业务代码。

所以真正的问题不是:

文件怎么上传?

而是:

如何让文件上传支持多种实现,并且以后新增实现时尽量少修改原来的代码?


二、策略模式解决什么问题?

策略模式可以简单理解成:

同一件事情存在多种实现方案,就把每一种方案单独封装起来。

例如文件上传统一定义一个能力:

FileStrategy

uploadFile()

然后不同存储平台分别实现:

FileStrategy
     ↑
     ├── MinioFileStrategy
     │
     ├── AliyunOSSFileStrategy
     │
     └── QiniuFileStrategy

也就是说:

MinioFileStrategy

只负责 Minio。

AliyunOSSFileStrategy

只负责阿里云。

以后增加七牛云:

QiniuFileStrategy

也只负责七牛云。

所有策略都遵守相同的 FileStrategy 接口,因此上层业务可以统一通过接口调用。教程中也是先定义 FileStrategy,再分别创建 Minio 和 Aliyun 两套实现。


三、为什么还需要工厂模式?

策略模式解决了:

有哪些上传方案?

但是还有一个问题:

系统现在到底应该使用哪一个方案?

这就是工厂模式负责的事情。

例如配置:

storage:
  type: aliyun

表示:

当前使用阿里云 OSS

如果修改成:

storage:
  type: minio

表示:

当前使用 Minio

然后交给工厂判断:

storage.type
      ↓
FileStrategyFactory
      ↓
选择具体策略

例如:

aliyun
 ↓
AliyunOSSFileStrategy

或者:

minio
 ↓
MinioFileStrategy

教程中的 FileStrategyFactory 就是读取 storage.type,然后决定创建 Minio 还是 Aliyun 的策略实现。

所以可以记成:

策略模式负责提供方案,工厂模式负责选择方案。


四、Service 为什么只依赖接口?

真正的业务层不会直接写:

MinioFileStrategy

也不会直接写:

AliyunOSSFileStrategy

而是依赖:

FileStrategy

也就是说:

FileService
     ↓
FileStrategy

Service 的想法很简单:

我只管上传文件,至于具体使用哪家存储,我不关心。

所以业务代码只需要调用:

fileStrategy.uploadFile()

真正执行 Minio 还是 Aliyun,由前面的工厂决定。教程中的 FileServiceImpl 正是只注入 FileStrategy 接口,而不是依赖具体实现类。

这样就实现了:

业务层和具体存储平台解耦。


五、完整业务流程

假设当前配置:

storage.type = aliyun

项目启动时:

读取配置
   ↓
storage.type = aliyun
   ↓
FileStrategyFactory
   ↓
创建 AliyunOSSFileStrategy
   ↓
交给 Spring 容器

然后:

FileService
   ↓
注入 FileStrategy

实际上得到的是:

AliyunOSSFileStrategy

当用户上传文件:

客户端
   ↓
FileController
   ↓
FileService
   ↓
fileStrategy.uploadFile()
   ↓
AliyunOSSFileStrategy
   ↓
上传到阿里云 OSS

如果把配置修改为:

storage.type = minio

流程就会变成:

客户端
   ↓
Controller
   ↓
Service
   ↓
fileStrategy.uploadFile()
   ↓
MinioFileStrategy
   ↓
上传到 Minio

Controller 不需要修改。

Service 也不需要修改。

真正变化的只是底层策略。

教程最终也是通过修改 storage.type,验证了 Minio 和 Aliyun 两种实现可以切换,而 Service 层无需变化。


六、为什么文件上传特别适合这种设计?

因为文件上传具有一个非常典型的特点:

业务目标固定,但是实现方式很多。

业务层看到的永远都是:

上传文件

但是底层可能是:

Minio SDK
阿里云 OSS SDK
七牛云 SDK
腾讯云 COS SDK

这正是策略模式最典型的应用场景。

类似的业务还有很多,例如:

支付
├── 微信支付
├── 支付宝
└── 银联

或者:

消息通知
├── 短信
├── 邮件
└── 微信消息

或者:

登录方式
├── 手机号登录
├── 微信登录
└── GitHub 登录

它们都有一个共同特点:

同一个业务目标,存在多个可以互相替换的实现方案。


七、以后新增存储平台怎么办?

假设以后增加:

七牛云

原来的结构:

FileStrategy
     ↑
     ├── MinioFileStrategy
     └── AliyunOSSFileStrategy

只需要增加:

FileStrategy
     ↑
     ├── MinioFileStrategy
     ├── AliyunOSSFileStrategy
     └── QiniuFileStrategy

然后让工厂能够识别:

qiniu
 ↓
QiniuFileStrategy

Service 仍然还是:

fileStrategy.uploadFile()

不用修改。

这就是这种设计最大的价值:

新增一种实现,尽量通过增加新代码完成,而不是不断修改旧业务代码。


八、什么时候适合使用策略模式?

比较适合下面几类场景。

第一种:

同一业务存在多种实现

例如:

文件存储
支付
登录
消息通知
算法选择

第二种:

实现方式可能经常切换

例如:

开发环境用 Minio
生产环境用阿里云 OSS

第三种:

未来可能继续增加新的实现

例如现在:

Minio + Aliyun

未来:

Minio + Aliyun + Qiniu + COS

这时候策略模式会非常适合。


九、什么时候没必要用?

设计模式不是越多越好。

如果你的系统明确:

永远只使用 Minio

而且几乎没有切换存储平台的可能,那么直接写:

MinioFileService

完全没有问题。

没必要为了一个实现,强行设计:

接口
策略
工厂
多个配置

否则只会增加代码复杂度。

所以是否使用策略模式,要看业务是否真的存在:

多种可替换实现。

如果只有一种实现,简单写通常更合适。


十、策略模式和工厂模式分别负责什么?

最后把两者彻底分清。

策略模式

解决:

有哪些实现方案?

例如:

FileStrategy
     ↑
     ├── Minio
     ├── Aliyun
     └── Qiniu

核心思想:

把不同实现拆开。

工厂模式

解决:

当前到底选择哪个实现?

例如:

storage.type
      ↓
Factory
      ↓
选择 Strategy

核心思想:

把对象的选择和创建集中起来。

两者结合:

配置
 ↓
工厂模式
 ↓
选择具体策略
 ↓
策略模式
 ↓
Minio / Aliyun / Qiniu
 ↓
Service 使用

十一、总结

文件上传使用“策略模式 + 工厂模式”,并不是因为上传文件本身很复杂。

真正的原因是:

底层存储方式可能变化。

策略模式负责:

Minio
Aliyun
Qiniu

这些不同上传方式的隔离。

工厂模式负责:

当前到底使用哪一个?

而 Service 永远只需要:

上传文件

最终形成:

Controller
   ↓
FileService
   ↓
FileStrategy
   ↓
Factory 选择具体实现
   ↓
Minio / Aliyun / 其他对象存储

可以简单记成一句话:

策略模式负责“有哪些方案”,工厂模式负责“选择哪个方案”,业务层只负责“调用方案”。

这种设计真正适合的,是:

同一个业务动作存在多种实现,而且这些实现未来可能切换或继续增加的场景。

策略模式 + 工厂模式:让文件上传支持多种存储方案
https://clxhxhhr.top/posts/2942/
作者
clxstart
发布于
2026-09-20
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。