目录
一、深入理解策略模式的设计思想、掌握在其分布式消息场景中的应用价值
[1.1 什么是策略模式?](#1.1 什么是策略模式?)
[1.2 为什么要用策略模式?](#1.2 为什么要用策略模式?)
[1.3 策略模式解决方案](#1.3 策略模式解决方案)
[1.4 策略模式的核心价值](#1.4 策略模式的核心价值)
[1.5 策略模式的结构](#1.5 策略模式的结构)
[1.6 适用场景判断](#1.6 适用场景判断)
[1.7 注意事项](#1.7 注意事项)
[2.1 需求背景](#2.1 需求背景)
[2.2 架构设计](#2.2 架构设计)
[2.3 代码实现](#2.3 代码实现)
[2.4 注意事项](#2.4 注意事项)
一、深入理解策略模式的设计思想、掌握在其分布式消息场景中的应用价值
1.1 什么是策略模式?
-
打个比方:策略模式就像"出行方式选择器"
-
你要去某个目的地,可以选择:开车、坐地铁、打车、骑车、步行
-
每种出行方式就是一条"策略"
-
你只需要告诉选择器"我要去XX",选择器会根据情况帮你选最合适的方式
-
你不需要关心每种方式的具体实现(开车怎么开、地铁怎么坐)
-
-
生活中的策略模式:
-
支付方式:微信、支付宝、银行卡、现金 → 支付时选择一种即可
-
排序算法:快排、归并、堆排序 → 根据数据特点选择最优算法
-
压缩方式:ZIP、RAR、7Z → 根据需求选择压缩策略
-
1.2 为什么要用策略模式?
- 问题场景:假设有三种业务消息要发送
java
// 传统写法:大量if-else
public void sendMessage(String type, Object data) {
if ("RESUME".equals(type)) {
// 简历分析的发送逻辑(20行代码)
} else if ("INTERVIEW".equals(type)) {
// 面试创建的发送逻辑(20行代码)
} else if ("DIALOGUE".equals(type)) {
// 对话消息的发送逻辑(20行代码)
}
// 后续新增业务类型,继续加else if...
}
- 传统写法的痛点 :
-
代码臃肿:所有逻辑堆在一个方法里,几百行代码
-
职责混乱:简历逻辑、面试逻辑、对话逻辑混在一起
-
改一处怕出错:修改简历逻辑,可能影响面试逻辑
-
扩展困难:新增业务类型要改原代码,违反开闭原则
-
1.3 策略模式解决方案

1.4 策略模式的核心价值
-
开闭原则:对扩展开放,对修改关闭
-
新增业务类型:只需添加新的策略类,无需修改现有代码
-
比如:要新增"直播面试"类型,只需加一个LiveInterviewStrategy类
-
-
单一职责:每个策略类只负责一件事
-
ResumeStrategy只管简历消息
-
InterviewStrategy只管面试消息
-
互不干扰,边界清晰
-
-
便于测试:每个策略类可独立单元测试
-
运行时切换:根据条件动态选择策略
1.5 策略模式的结构

1.6 适用场景判断
-
适合用策略模式:
-
有多个类只是行为差异,可以用策略来切换
-
需要在运行时选择算法或策略
-
业务有很多if-else分支,且分支条件固定
-
-
不适合用策略模式:
-
策略数量很少(1-2个),简单if-else就够了
-
策略之间差异很小,没必要拆分
-
策略经常变化,频繁新增删除
-
1.7 注意事项
-
不要过度设计:简单场景用简单方案
-
策略数量控制:策略过多时要考虑合并或拆分
-
客户端要了解策略:调用方需要知道有哪些策略可用
二、多类型权益消息策略模式接口设计与工厂实现
2.1 需求背景
-
业务MQ消息发送的挑战:
-
业务类型多样:简历分析、面试创建等不同业务类型
-
消息格式各异:每种业务需要不同的消息体结构
-
路由规则不同:不同业务消息需要路由到不同队列
-
-
策略模式的价值:
-
开闭原则:新增业务类型只需添加策略实现,无需修改现有代码
-
单一职责:每个策略类只负责一种消息发送逻辑
-
解耦业务逻辑:调用方无需了解具体消息发送细节
-
2.2 架构设计

2.3 代码实现
策略接口定义(common模块)
java
/**
* 权益消息发送策略接口
* 用于ai-service发送不同类型的业务MQ消息
*
* 设计说明:
* - 策略接口定义在common模块,便于共享
* - 策略实现在ai-service,与业务逻辑内聚
* - account-service只负责权益扣减和延迟检查,不发送业务MQ
*/
public interface BenefitMessageStrategy {
/**
* 发送业务消息
* 由ai-service在权益扣减成功后调用
*
* @param messageId 消息ID(任务ID,用于关联延迟检查)
* @param businessId 业务ID(简历ID/面试ID)
* @param accountId 账号ID
*/
void sendBusinessMessage(String messageId, String businessId, Long accountId);
/**
* 获取策略类型(对应权益编码)
*
* @return 权益编码
*/
String getStrategyType();
}
策略工厂实现
java
@Component
@Slf4j
public class BenefitMessageStrategyFactory {
private final Map<String, BenefitMessageStrategy> strategyMap = new ConcurrentHashMap<>();
/**
* 构造函数注入所有策略实现
* Spring会自动注入所有BenefitMessageStrategy的实现类
*/
@Autowired
public BenefitMessageStrategyFactory(List<BenefitMessageStrategy> strategies) {
for (BenefitMessageStrategy strategy : strategies) {
strategyMap.put(strategy.getStrategyType(), strategy);
log.info("注册权益消息策略: {} -> {}",
strategy.getStrategyType(), strategy.getClass().getSimpleName());
}
}
/**
* 根据权益编码获取策略
* 支持精确匹配和类型匹配(面试类型统一处理)
*/
public BenefitMessageStrategy getStrategy(String benefitCode) {
// 1. 先精确匹配
BenefitMessageStrategy strategy = strategyMap.get(benefitCode);
if (strategy != null) {
return strategy;
}
// 2. 面试类型使用统一的面试策略
if (isInterviewType(benefitCode)) {
strategy = strategyMap.get("INTERVIEW");
if (strategy != null) {
return strategy;
}
}
throw new IllegalArgumentException("未找到权益编码对应的消息策略: " + benefitCode);
}
private boolean isInterviewType(String benefitCode) {
try {
BenefitEnum benefitEnum = BenefitEnum.valueOf(benefitCode);
return benefitEnum == BenefitEnum.SPECIAL_INTERVIEW
|| benefitEnum == BenefitEnum.COMMON_INTERVIEW;
} catch (Exception e) {
return false;
}
}
}
2.4 注意事项
-
接口放common模块:便于多个服务共享策略接口定义
-
实现放ai-service:消息发送逻辑与业务服务内聚
-
自动注册策略:利用Spring的List注入自动收集所有策略实现
-
线程安全:使用ConcurrentHashMap保证并发安全