面试官:你在项目里使用过工厂模式吗?
你:使用过,我记得Spring就是使用的工厂模式,工厂模式是……。
面试官:……嗯,说的对,但我问的是你项目里使没使用过,不是框架里。
你:啊额,不好意思,没使用过。
面试官:那行,你回去等通知吧!
你:哇呜呜
🌿 一、场景描述
系统中需要支持多种消息发送方式:
- 短信
- 邮件
- 微信(假设后续新增)
如果不使用设计模式,最直觉的方式是:
if (type.equals("email")) {
// 发送邮件逻辑
} else if (type.equals("sms")) {
// 发送短信逻辑
}
⚠️ 缺点:
- 每新增一种消息,都要修改 if/else,违反开闭原则(对扩展开放,对修改关闭)。
- 耦合严重,代码难以维护、测试、扩展。
🌸 二、工厂模式优雅解决
核心思想: 将消息发送逻辑进行抽象,不同消息发送器实现同一个接口,通过工厂创建对应发送器,屏蔽具体实现细节。
1. 定义消息发送器接口(顶层标准)
public interface MessageSender {
void sendMessage(String message);
}
2. 实现不同消息发送器(多种实现方式)
// 短信发送器
public class SmsSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送短信: " + message);
// 实际调用短信服务API
}
}
// 邮件发送器
public class EmailSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送邮件: " + message);
// 实际调用邮件服务API
}
}
3. 创建消息发送器工厂(统一创建对象)
public class MessageSenderFactory {
public static MessageSender getSender(String type) {
if ("sms".equalsIgnoreCase(type)) {
return new SmsSender();
} else if ("email".equalsIgnoreCase(type)) {
return new EmailSender();
} else {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
}
}
4. 调用示例(对外统一)
public class Main {
public static void main(String[] args) {
MessageSender smsSender = MessageSenderFactory.getSender("sms");
smsSender.sendMessage("您的验证码是 1234");
MessageSender emailSender = MessageSenderFactory.getSender("email");
emailSender.sendMessage("欢迎注册我们的网站!");
}
}
🌲 三、如果新增一种“微信消息”怎么办?
无需修改现有逻辑,只需:
- 实现一个新的
WeChatSender
类。 - 在
MessageSenderFactory
中新增分支,或者使用更优雅的注册方式(后面扩展讲)。
public class WeChatSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送微信: " + message);
}
}
🌟 四、更优雅的优化(去掉 if/else,改成 Map 注册)
为了避免 MessageSenderFactory
里 if/else 越来越长,可以用 Map 注册管理:
public class MessageSenderFactory {
private static final Map<String, MessageSender> senderMap = new HashMap<>();
static {
senderMap.put("sms", new SmsSender());
senderMap.put("email", new EmailSender());
senderMap.put("wechat", new WeChatSender()); // 新增
}
public static MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type.toLowerCase());
if (sender == null) {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
return sender;
}
}
✅ 优点:
- 解耦扩展,新增一种类型只需要注册即可,无需修改其他代码。
- 统一接口调用,方便测试、维护。
💡 五、总结:工厂模式解决的问题
问题 | 工厂模式的解决方式 |
---|---|
创建对象逻辑复杂 | 把对象创建交给工厂,调用方不用管细节 |
新增消息发送方式需要修改大量代码 | 只需新增实现类,工厂注册即可,扩展方便 |
调用方与实现类耦合严重 | 通过接口+工厂解耦,调用方只依赖接口 |
代码冗长难维护 | 工厂集中管理创建,易于维护 |
🚀 六、现实项目中如何落地?
- 抽象接口(如消息发送器标准、支付方式标准等)。
- 具体实现(不同消息类型、不同支付方式)。
- 工厂模式管理创建,配合 Spring 容器、Bean 工厂可以自动注入管理。
- 使用场景:
- 消息发送(短信、邮件、微信、站内信)。
- 支付(微信、支付宝、银行卡等)。
- 文件存储(本地、阿里OSS、腾讯COS等)。
- 日志收集器(本地文件、数据库、ES等)。
🌿 七、问题引入:传统工厂模式的问题
在刚才的 Map 注册方式 中,你有没有发现:
static {
senderMap.put("sms", new SmsSender());
senderMap.put("email", new EmailSender());
senderMap.put("wechat", new WeChatSender()); // 新增
}
🔴 缺点:
- 每次新增一种发送器,还得 手动在静态块中注册。
- 如果发送器越来越多,管理成本高,不符合开闭原则。
那么有没有更好的办法?当然有!
🌸 八、结合 Spring 容器自动管理 —— 实现动态扩展
我们把消息发送器的实现类,交给 Spring 管理,并动态识别和注册。
⭐ 核心目标:
- 新增实现类不动工厂逻辑,自动识别和注册。
- 灵活切换消息发送方式。
- 和工厂结合,屏蔽具体实现细节。
🌲 九、实现步骤
1. 定义统一接口(抽象标准)
public interface MessageSender {
void sendMessage(String message);
String getType(); // 新增方法,返回具体类型,如 "sms"、"email"
}
getType 用来标识发送器的类型,供工厂自动识别。
2. 实现不同发送器(自动交给Spring管理)
@Component
public class SmsSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送短信: " + message);
}
@Override
public String getType() {
return "sms";
}
}
@Component
public class EmailSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送邮件: " + message);
}
@Override
public String getType() {
return "email";
}
}
🌟 注意:加上
@Component
注解,自动注册为 Spring Bean。
3. 工厂类,自动注入所有实现(动态注册)
@Component
public class MessageSenderFactory {
// Spring 会自动注入所有实现 MessageSender 接口的 Bean
private final Map<String, MessageSender> senderMap = new HashMap<>();
@Autowired
public MessageSenderFactory(List<MessageSender> messageSenders) {
for (MessageSender sender : messageSenders) {
senderMap.put(sender.getType(), sender); // 动态注册
}
}
public MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type);
if (sender == null) {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
return sender;
}
}
✅ 亮点:
- 自动扫描所有实现,无需手动注册。
- 每个实现类自行返回 type,动态识别。
- 轻松扩展,新加微信发送器,仅需新增实现类,无需修改工厂!
4. 使用示例(Controller 或 Service 中调用)
@RestController
@RequestMapping("/message")
public class MessageController {
@Autowired
private MessageSenderFactory factory;
@PostMapping("/send")
public String send(@RequestParam String type, @RequestParam String content) {
MessageSender sender = factory.getSender(type);
sender.sendMessage(content);
return "消息已发送";
}
}
🔥 动态选择发送器:
POST /message/send?type=sms&content=你好
POST /message/send?type=email&content=Hello Email
✨ 十、效果总结
问题 | 传统工厂模式 | Spring 结合改进后 |
---|---|---|
新增消息类型 | 需要修改工厂注册逻辑 | 仅新增实现类,自动识别 |
耦合度 | 高 | 低 |
扩展性 | 较差 | 极强 |
管理成本 | 高,容易遗漏 | 低,自动托管 |
🌻 十一、如果继续新增新消息器如微信?
@Component
public class WeChatSender implements MessageSender {
@Override
public void sendMessage(String message) {
System.out.println("发送微信: " + message);
}
@Override
public String getType() {
return "wechat";
}
}
✅ 工厂不需要动一行代码!系统自动支持
🌟 十二、总结一句话
工厂模式 + 策略模式 + Spring IOC 自动托管
实现了一个 高扩展性、低耦合、易维护 的消息发送器体系,符合真正的企业级项目开发标准!