本文主要介绍了简单工厂模式,包括其定义、结构、实现方式、适用场景、实战示例以及思考。简单工厂模式是一种创建型设计模式,通过工厂类根据参数决定创建哪一种产品类的实例,封装了对象创建的细节,使客户端无需关心具体类的创建逻辑。文章详细阐述了其角色组成、类图、时序图,探讨了两种常见的实现方式,分析了适合与不适合的场景,并提供了 Spring 项目和可插拔式策略工厂的实战示例。最后,还提出了支持 SPI 机制、注解标记策略名称和配置中心切换策略等思考方向。
简单工厂模式是一种创建型设计模式,它通过一个工厂类根据传入的参数决定创建哪一种产品类的实例。
核心要点:
组成结构:
角色 |
说明 |
Product |
抽象产品类(接口或抽象类) |
ConcreteProduct |
具体产品类,实现 Product 接口 |
Factory |
工厂类,包含创建产品对象的静态方法 |
Client |
客户端,调用工厂方法获取产品对象并使用它 |
实现方式主要分为两种:
实现方式 |
描述 |
1. 静态方法创建(常用) |
工厂方法是 |
2. 实例方法创建(灵活) |
工厂需要先实例化,再调用方法创建对象,适合支持不同配置或依赖注入 |
// 抽象产品
public interface Product {
void doWork();
}
// 具体产品 A
public class ProductA implements Product {
public void doWork() {
System.out.println("产品A正在工作");
}
}
// 具体产品 B
public class ProductB implements Product {
public void doWork() {
System.out.println("产品B正在工作");
}
}
// 简单工厂
public class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equalsIgnoreCase(type)) {
return new ProductA();
} else if ("B".equalsIgnoreCase(type)) {
return new ProductB();
}
throw new IllegalArgumentException("不支持的产品类型:" + type);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Product product = SimpleFactory.createProduct("A");
product.doWork(); // 输出:产品A正在工作
}
}
// 工厂类
public class SimpleFactory {
public Product createProduct(String type) {
if ("A".equalsIgnoreCase(type)) {
return new ProductA();
} else if ("B".equalsIgnoreCase(type)) {
return new ProductB();
}
throw new IllegalArgumentException("不支持的产品类型:" + type);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
SimpleFactory factory = new SimpleFactory();
Product product = factory.createProduct("B");
product.doWork(); // 输出:产品B正在工作
}
}
对比项 |
静态方法工厂 |
实例方法工厂 |
是否需要工厂对象 |
否 |
是 |
是否支持配置 |
较差 |
支持通过构造函数注入 |
使用场景 |
通用工厂、工具类 |
多配置或状态的工厂类 |
场景描述 |
原因 |
产品种类有限,变化不大 |
工厂中 if-else/switch 可维护性尚可,结构清晰 |
客户端不关心对象创建细节 |
封装了具体类的创建过程,减少耦合 |
多个子类实现一个接口/抽象类,客户端按条件选择创建哪一个 |
工厂根据传参决定具体返回哪个子类 |
代码结构相对简单,开发阶段处于初期 |
不想引入复杂设计,简单工厂最直观、易懂 |
希望集中管理对象创建 |
比 scattered new 更好维护和修改 |
示例:日志输出、支付方式选择、消息发送器选择(短信/邮件/微信)等。
场景描述 |
问题 |
1. 产品种类经常变化或增加 |
每新增一个产品都要修改工厂类,违反“开放封闭原则” |
2. 产品种类太多,逻辑复杂 |
工厂类会膨胀成一个巨大类,不利于维护 |
3. 需要依赖注入、构造过程复杂 |
无法灵活注入依赖,缺乏拓展性 |
4. 对产品创建过程有定制要求 |
不能对不同产品的创建过程进行细粒度控制 |
5. 分布式、多模块开发场景 |
集中式工厂类会形成模块间强依赖,不利于解耦和部署 |
示例:大型系统中涉及复杂对象生命周期控制的场景(如数据库连接池、线程池、配置驱动类等)。
建议 |
原因 |
✔ 使用于产品稳定、变化少的小规模项目 |
简单、易维护 |
❌ 不建议用于大型、产品体系复杂的项目 |
违背开闭原则、扩展性差 |
可结合工厂方法模式或抽象工厂模式演进 |
更好地支持扩展与解耦 |
我们以“消息发送系统”为例,演示如何使用简单工厂根据输入创建不同的消息发送器(如短信、邮件、微信等)。
在 Spring 项目中,根据配置选择不同的消息发送器进行发送,如:
sms
:发送短信;email
:发送邮件;wechat
:发送微信。public interface MessageSender {
void send(String message);
}
@Component("smsSender")
public class SmsSender implements MessageSender {
public void send(String message) {
System.out.println("发送短信:" + message);
}
}
@Component("emailSender")
public class EmailSender implements MessageSender {
public void send(String message) {
System.out.println("发送邮件:" + message);
}
}
@Component("wechatSender")
public class WechatSender implements MessageSender {
public void send(String message) {
System.out.println("发送微信:" + message);
}
}
@Component
public class MessageSenderFactory {
@Autowired
private ApplicationContext applicationContext;
public MessageSender createSender(String type) {
switch (type.toLowerCase()) {
case "sms":
return applicationContext.getBean("smsSender", MessageSender.class);
case "email":
return applicationContext.getBean("emailSender", MessageSender.class);
case "wechat":
return applicationContext.getBean("wechatSender", MessageSender.class);
default:
throw new IllegalArgumentException("不支持的消息类型:" + type);
}
}
}
@Service
public class NotifyService {
@Autowired
private MessageSenderFactory messageSenderFactory;
// 模拟从配置文件或参数中读取类型
@Value("${message.type:sms}")
private String messageType;
public void notifyUser(String content) {
MessageSender sender = messageSenderFactory.createSender(messageType);
sender.send(content);
}
}
@RestController
public class MessageController {
@Autowired
private NotifyService notifyService;
@GetMapping("/send")
public String send(@RequestParam String msg) {
notifyService.notifyUser(msg);
return "消息已发送";
}
}
application.yml
示例配置message:
type: email
设计点 |
说明 |
工厂类 |
|
接口统一 |
所有发送器实现 |
解耦 |
|
可配置 |
支持通过配置控制行为,符合 Spring 项目实践 |
下面是一个 可插拔式策略工厂(基于 Map 注册 + Spring 管理) 的完整示例,非常适用于需要动态切换、按配置扩展的业务策略类,比如:消息发送、支付渠道、风控策略、营销活动处理器等。实现一种 灵活可扩展 的策略选择工厂,每个策略自动注册 到一个 Map
中,不需要手动 switch-case
。
public interface MessageSender {
String type(); // 每个实现类提供自己的标识
void send(String message);
}
@Component
public class SmsSender implements MessageSender {
public String type() {
return "sms";
}
public void send(String message) {
System.out.println("【短信】发送:" + message);
}
}
@Component
public class EmailSender implements MessageSender {
public String type() {
return "email";
}
public void send(String message) {
System.out.println("【邮件】发送:" + message);
}
}
@Component
public class WechatSender implements MessageSender {
public String type() {
return "wechat";
}
public void send(String message) {
System.out.println("【微信】发送:" + message);
}
}
@Component
public class MessageSenderFactory {
private final Map senderMap = new HashMap<>();
// Spring 会自动注入所有 MessageSender 的实现类
@Autowired
public MessageSenderFactory(List senders) {
for (MessageSender sender : senders) {
senderMap.put(sender.type(), sender);
}
}
public MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type);
if (sender == null) {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
return sender;
}
}
@Service
public class NotifyService {
@Autowired
private MessageSenderFactory messageSenderFactory;
public void notifyUser(String type, String content) {
MessageSender sender = messageSenderFactory.getSender(type);
sender.send(content);
}
}
@RestController
@RequestMapping("/msg")
public class MessageController {
@Autowired
private NotifyService notifyService;
@GetMapping("/send")
public String send(@RequestParam String type, @RequestParam String msg) {
notifyService.notifyUser(type, msg);
return "消息已发送";
}
}
请求:
GET /msg/send?type=sms&msg=Hello_SMS
GET /msg/send?type=email&msg=Hello_Email
GET /msg/send?type=wechat&msg=Hello_WeChat
输出:
【短信】发送:Hello_SMS
【邮件】发送:Hello_Email
【微信】发送:Hello_WeChat
特性 |
说明 |
可插拔 |
新增一个实现类即可生效,无需改动工厂或业务代码 |
高扩展性 |
支持多策略、动态注册 |
易维护 |
摆脱 if-else / switch |
Spring友好 |
利用 Spring 自动注入 & 生命周期 |
@Value("${message.type}")
注入默认策略。下面是一个完整的 基于 Java SPI(Service Provider Interface)机制的插件式策略工厂实现示例,它常用于实现模块解耦、可插拔、动态扩展功能。以“消息发送策略”为例,不使用 Spring 注解扫描,而是通过 SPI 机制动态加载所有实现类。
// src/main/java/com/example/spi/MessageSender.java
package com.example.spi;
public interface MessageSender {
String type(); // 返回类型标识符
void send(String message); // 发送消息逻辑
}
// src/main/java/com/example/impl/SmsSender.java
package com.example.impl;
import com.example.spi.MessageSender;
public class SmsSender implements MessageSender {
@Override
public String type() {
return "sms";
}
@Override
public void send(String message) {
System.out.println("【短信发送】" + message);
}
}
在 jar 包中的 resources/META-INF/services/
路径下创建文件:
META-INF/services/com.example.spi.MessageSender
内容如下(每一行一个实现类的全限定名):
com.example.impl.SmsSender
✅ 当你有多个策略实现时,添加多行即可,如:
com.example.impl.SmsSender
com.example.impl.EmailSender
package com.example.factory;
import com.example.spi.MessageSender;
import java.util.*;
public class MessageSenderFactory {
private final Map senderMap = new HashMap<>();
public MessageSenderFactory() {
// 加载spi接口所有接口实现类
ServiceLoader loader = ServiceLoader.load(MessageSender.class);
for (MessageSender sender : loader) {
senderMap.put(sender.type(), sender);
}
}
public MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type);
if (sender == null) {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
return sender;
}
}
ServiceLoader loader = ServiceLoader.load(MessageSender.class);
是 Java 原生 SPI(Service Provider Interface)机制 的核心。它的底层原理其实并不复杂,是通过读取类路径下的 META-INF/services/
目录下的文件,并利用反射机制加载实现类。以下是 ServiceLoader
的简化执行逻辑:
// 从 META-INF/services/ 下查找接口对应的配置文件
Enumeration urls = classLoader.getResources("META-INF/services/" + serviceClass.getName());
// 读取文件中的类名
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String implClassName = reader.readLine();
// 通过反射实例化对象
Class> clazz = Class.forName(implClassName);
Object instance = clazz.newInstance();
每个实现类会被加载成一个对象,并返回一个延迟加载的迭代器。
public class Main {
public static void main(String[] args) {
MessageSenderFactory factory = new MessageSenderFactory();
MessageSender sender = factory.getSender("sms");
sender.send("Hello SPI!");
}
}
src/
├── main/
│ ├── java/
│ │ ├── com.example.spi/MessageSender.java
│ │ ├── com.example.impl/SmsSender.java
│ │ └── com.example.factory/MessageSenderFactory.java
│ └── resources/
│ └── META-INF/services/com.example.spi.MessageSender
优点 |
说明 |
插件化、低耦合 |
实现类可来自外部 jar 包,主程序不需修改 |
动态扩展能力强 |
实现类可以热插拔(配合 OSGi、模块系统) |
框架内部广泛使用 |
Dubbo、JDBC、Spring Boot 自动配置( |
spring.factories
或 spring.factories
→ spring/org.springframework.boot.autoconfigure.EnableAutoConfiguration
)机制配合。在 策略模式 中,支持通过 注解 来标记每个策略的名称,可以极大提升策略类的可读性和扩展性,尤其适用于 SPI、Map 注册、Spring 容器注册等场景。
MessageSender
策略实现类@MessageType("sms")
)@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageType {
String value(); // 策略类型标识
}
public interface MessageSender {
void send(String message);
}
@MessageType("sms")
public class SmsSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("发送短信: " + message);
}
}
@MessageType("email")
public class EmailSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("发送邮件: " + message);
}
}
public class MessageSenderFactory {
private final Map senderMap = new HashMap<>();
public MessageSenderFactory() {
// SPI 加载所有 MessageSender 实现类
ServiceLoader loader = ServiceLoader.load(MessageSender.class);
for (MessageSender sender : loader) {
MessageType annotation = sender.getClass().getAnnotation(MessageType.class);
if (annotation != null) {
senderMap.put(annotation.value(), sender);
}
}
}
public MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type);
if (sender == null) {
throw new IllegalArgumentException("不支持的消息类型: " + type);
}
return sender;
}
}
public class Main {
public static void main(String[] args) {
MessageSenderFactory factory = new MessageSenderFactory();
factory.getSender("sms").send("验证码123456");
factory.getSender("email").send("欢迎邮件");
}
}
ServiceLoader
/Spring 配合使用,支持动态发现@Value("${message.type}")
注入默认策略。你希望实现一种 支持配置中心动态切换策略 的能力,例如通过配置中心的属性(如 Nacos、Apollo、Spring Cloud Config 等)控制当前策略的类型:实现思路(Spring + 注解 + Map 注册 + 配置驱动)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageType {
String value();
}
public interface MessageSender {
void send(String message);
}
@Component
@MessageType("sms")
public class SmsSender implements MessageSender {
public void send(String message) {
System.out.println("发送短信: " + message);
}
}
@Component
@MessageType("email")
public class EmailSender implements MessageSender {
public void send(String message) {
System.out.println("发送邮件: " + message);
}
}
@Component
public class MessageSenderFactory implements InitializingBean {
@Value("${message.type:email}") // 默认email,可由配置中心动态更新
private String defaultType;
@Autowired
private List senderList;
private final Map senderMap = new HashMap<>();
@Override
public void afterPropertiesSet() {
for (MessageSender sender : senderList) {
MessageType annotation = sender.getClass().getAnnotation(MessageType.class);
if (annotation != null) {
senderMap.put(annotation.value(), sender);
}
}
}
/*
* 如果使用默认方式,采用的就是nacos 配置策略
*/
public MessageSender getSender() {
MessageSender sender = senderMap.get(defaultType);
if (sender == null) {
throw new IllegalArgumentException("未找到对应的策略类型: " + defaultType);
}
return sender;
}
/*
* 使用入参对应的策略
*/
public MessageSender getSender(String type) {
MessageSender sender = senderMap.get(type);
if (sender == null) {
throw new IllegalArgumentException("未找到对应的策略类型: " + type);
}
return sender;
}
}
@RestController
public class MessageController {
@Autowired
private MessageSenderFactory factory;
/*
* 如果使用默认方式,采用的就是nacos配置策略
*/
@GetMapping("/send")
public String send(@RequestParam String msg) {
factory.getSender().send(msg);
return "消息已发送";
}
/*
* 如果使用入参对应方式发送
*/
@GetMapping("/email/send")
public String send(@RequestParam String sendType, @RequestParam String msg) {
factory.getSender(sendType).send(msg);
return "消息已发送";
}
}
如果你使用配置中心(如 Nacos),你还可以让 @Value("${message.type}")
自动刷新:
@RefreshScope
@Component
public class MessageSenderFactory implements InitializingBean {
...
}
这样,在 Nacos 修改 message.type=email
为 sms
,会实时切换策略。
特性 |
实现方式 |
策略标识 |
注解 |
扫描所有策略实现 |
Spring 注入 |
配置驱动选择策略 |
|
动态刷新策略选择 |
|
使用 SPI 机制(META-INF/services
) 和 普通简单工厂模式 都是实现“根据类型返回不同实现类”的策略工厂思想,但它们在实现机制、应用场景和扩展性上有很大不同。以下是详细对比和说明:
项目 |
SPI机制( |
简单工厂模式(自己注册/Map) |
加载方式 |
JDK 内置 自动发现实现类 |
自己手动注册,或用注解 + Spring 扫描 |
实现类注册位置 |
|
代码中通过 |
是否依赖容器(如Spring) |
否(纯 JDK 原生机制) |
是(通常依赖 Spring 注入、配置) |
扩展性(插件支持) |
强,可动态加入 jar 包扩展实现 |
弱,必须修改代码或重启注册逻辑 |
热插拔能力 |
支持(添加 jar 即生效,重启可用) |
不支持,必须重启或改代码 |
类型标识方式 |
实现类自己定义类型(如 |
通常用注解或手动 |
适合插件机制 |
✅ 非常适合 |
❌ 不适合 |
使用门槛 |
中(需要手动写 SPI 配置文件) |
低(代码中实现注册) |
MessageSender
EmailSender
、SmsSender
并实现该接口resources/META-INF/services/com.example.spi.MessageSender
文件中列出所有实现类的 全限定类名com.example.sender.EmailSender
com.example.sender.SmsSender
ServiceLoader
自动扫描并实例化:ServiceLoader loader = ServiceLoader.load(MessageSender.class);
for (MessageSender sender : loader) {
senderMap.put(sender.type(), sender);
}
实现类可以是外部 jar 包,插件式部署。无需改主程序代码。
实现逻辑通常在代码里“硬编码”注册每种类型与实现类的关系:
public class SenderFactory {
private static final Map map = new HashMap<>();
static {
map.put("email", new EmailSender());
map.put("sms", new SmsSender());
}
public static MessageSender getSender(String type) {
return map.get(type);
}
}
实现类和工厂强耦合,新增类型时,必须改代码、重编、重新部署。
场景 |
建议使用方式 |
插件式架构,第三方扩展点 |
✅ 使用 SPI |
配置中心控制策略选择 |
✅ 使用 Spring + Map |
内部服务、类型少且固定 |
✅ 简单工厂 |
支持 jar 级别热插拔、可拔插插件 |
✅ SPI + jar 模块化 |
多环境配置动态选择实现 |
✅ Spring 结合 @Value |