网站首页 > 教程文章 正文
一、为什么需要工厂模式+ 策略模式?
单独使用策略模式时,客户端需要直接实例化具体策略类(如 new AiAuditStrategy()),这会导致两个问题:
- 客户端与具体策略强耦合:客户端必须知道所有策略类的细节(如类名、构造参数),违反 “迪米特法则”。
- 策略创建逻辑重复:若策略的创建需要复杂逻辑(如参数校验、依赖注入、配置读取),这些代码会在客户端重复出现,违背 “单一职责原则”。
而工厂模式的核心是封装对象创建逻辑,通过工厂类统一管理策略的实例化过程。两者结合后,客户端只需通过工厂获取策略实例(如
AiAuditStrategyFactory.getMediaType(1)),无需关心具体策略如何创建或切换,同时保持策略的动态替换能力。
二、工厂模式 + 策略模式解决的核心问题
1. 解耦客户端与具体策略
客户端只需通过工厂获取策略接口,无需知道具体策略类的细节(如类名、构造参数),符合 “依赖倒置原则”。
2. 封装复杂的创建逻辑
策略的创建可能涉及参数校验、资源初始化(如数据库连接)、配置读取等逻辑,这些代码被集中封装在工厂中,避免重复。
3. 支持动态切换策略
通过工厂的 “类型参数” 或 “配置”,可以在运行时动态选择策略(如根据用户选择切换支付方式),无需修改客户端代码。
4. 符合开闭原则
新增策略时,只需添加新的策略类和工厂的创建逻辑(如在工厂中注册新策略类型),无需修改现有客户端代码,扩展性强。
三、工厂模式 + 策略模式实战
3.1 需求
有个后台管理系统,可以上传不同的资源类型(图片、音频和视频),上传后调用第三方接口进行机审,要求:尽可能少用 if else 、易维护、易扩展和增加策略后不需要修改客户端代码。
3.2 if else 实现
业务实现代码:
public interface AudioAuditService {
void audit(Integer mediaType);
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AudioAuditServiceImpl implements AudioAuditService {
public void audit(Integer mediaType) {
log.info("## audit param mediaType:{}", mediaType);
if (mediaType == 1) {
// 业务实现简略
System.out.println("视频机审, 调用腾讯AI机审接口");
} else if (mediaType == 2) {
// 业务实现简略
System.out.println("音频机审, 调用腾讯AI机审接口");
} else if (mediaType == 3) {
// 业务实现简略
System.out.println("图片机审, 调用腾讯AI机审接口");
}
}
}
客户端代码:
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AudioAuditServiceImpl implements AudioAuditService {
public void audit(Integer mediaType) {
log.info("## audit param mediaType:{}", mediaType);
if (mediaType == 1) {
// 业务实现简略
System.out.println("视频机审, 调用腾讯AI机审接口");
} else if (mediaType == 2) {
// 业务实现简略
System.out.println("音频机审, 调用腾讯AI机审接口");
} else if (mediaType == 3) {
// 业务实现简略
System.out.println("图片机审, 调用腾讯AI机审接口");
}
}
}
使用postman模拟请求:
执行结果截图:
3.3 工厂模式 + 策略模式实现
策略类:
public interface AiAuditStrategy {
default void audit() {
throw new RuntimeException("此资源类型没有AI审核!");
}
}
工厂类:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class AiAuditStrategyFactory {
// 使用ConcurrentHashMap管理所有的策略,避免并发请求产生线程安全问题
private static Map<Integer, AiAuditStrategy> map = new ConcurrentHashMap<>();
public static AiAuditStrategy getMediaType(Integer type) {
return map.get(type);
}
public static void register(Integer type, AiAuditStrategy strategy) {
map.put(type, strategy);
}
}
以下策略实现类均通过 Spring 的 InitializingBean 注册策略类
视频策略实现:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
@Service
public class VideoAiAuditStrategy implements AiAuditStrategy, InitializingBean {
@Override
public void afterPropertiesSet() {
AiAuditStrategyFactory.register(1, this);
}
@Override
public void audit() {
// 业务实现简略
System.out.println("策略模式-视频机审, 调用腾讯AI机审接口");
}
}
音频策略实现:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
@Service
public class AudioAiAuditStrategy implements AiAuditStrategy, InitializingBean {
@Override
public void afterPropertiesSet() {
AiAuditStrategyFactory.register(2, this);
}
@Override
public void audit() {
// 业务实现简略
System.out.println("策略模式-音频机审, 调用腾讯AI机审接口");
}
}
图片策略实现:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
@Service
public class ImageAiAuditStrategy implements AiAuditStrategy, InitializingBean {
@Override
public void afterPropertiesSet() {
AiAuditStrategyFactory.register(3, this);
}
@Override
public void audit() {
// 业务实现简略
System.out.println("策略模式-图片机审, 调用腾讯AI机审接口");
}
}
客户端代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/media-resources")
public class MediaResourcesController {
@Autowired
private AudioAuditService audioAuditService ;
@PostMapping("/audit2")
public String audit2(@RequestParam Integer mediaType) {
AiAuditStrategyFactory.getMediaType(mediaType).audit();
return "OKK";
}
}
使用postman模拟请求:
执行结果截图:
工厂加策略模式完美实现上述需求,消除 if else 、易维护、易扩展、增加策略后不需要修改客户端代码,直接添加策略类即可。
– 欢迎点赞、关注、转发、收藏【技术咖啡馆C】,各大平台同名。
- 上一篇: 深度剖析:从迷茫到精通,我用「三层递进法」拆解复杂Java项目
- 下一篇: 20. 综合项目
猜你喜欢
- 2025-08-03 Chrome插件Talend API Tester核心竞争力与功能深度解析
- 2025-08-03 十分钟带你了解阿里、美团、滴滴、头条等互联网头部大厂面经
- 2025-08-03 什么是RPC?什么是Restful?它们有什么区别?
- 2025-08-03 基于Java实现,支持在线发布API接口读取数据库,有哪些工具?
- 2025-08-03 最近做了一个搜索接口的优化,反复压测了四次,终于达到要求了
- 2025-08-03 HTTP链接保活,3个层面的保活机制,让你的认知入木三分
- 2025-08-03 每天一个 Python 库:httpx异步请求,让接口测试飞起来
- 2025-08-03 20. 综合项目
- 2025-08-03 架构篇-一分钟掌握性能优化小技巧
- 2025-08-03 深度剖析:从迷茫到精通,我用「三层递进法」拆解复杂Java项目
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)