工厂模式(Factory Pattern)
一句话理解:工厂模式 = 对象的"代工厂",告别 new 满天飞,让创建对象像点外卖一样简单!
作用
- 统一创建对象,避免 new 到处乱飞
- 把对象创建逻辑集中管理,改一处,全局生效
适用场景
| 场景 | 说明 |
|---|---|
| ✅ 多种实现类选择 | 如:支付宝/微信/银行卡支付 |
| ✅ 根据类型动态创建对象 | 如:根据配置创建不同数据库连接 |
| ✅ 解耦业务 | 业务代码不直接依赖具体实现类 |
| ✅ 对象创建逻辑复杂 | 需要初始化很多参数 |
生活类比
| 方式 | 描述 |
|---|---|
| ❌ 没有工厂模式 | 你自己和面、烤面包、煎肉饼做汉堡... |
| ✅ 使用工厂模式 | 直接告诉麦当劳:"来个巨无霸" 🍔 |
代码结构图解
scss
┌─────────────────────────────────────────────────────────────┐
│ 客户端 (Client) │
│ "我要一个产品!" │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 工厂 (Factory) │
│ ┌─────────────────────────┐ │
│ │ createProduct(type) │ │
│ │ - 根据类型判断 │ │
│ │ - 返回对应产品 │ │
│ └─────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ 产品 A │ │ 产品 B │ │ 产品 C │
│ (ProductA) │ │ (ProductB) │ │ (ProductC) │
└────────────┘ └────────────┘ └────────────┘
核心代码示例
1. 定义产品接口
java
public interface PaymentService {
void pay(BigDecimal amount);
}
2. 具体产品实现
java
public class AlipayService implements PaymentService {
@Override
public void pay(BigDecimal amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
}
public class WechatPayService implements PaymentService {
@Override
public void pay(BigDecimal amount) {
System.out.println("使用微信支付:" + amount + "元");
}
}
3. 工厂类(核心!)
java
public class PaymentFactory {
private PaymentFactory() {} // 私有构造,禁止外部 new
public static PaymentService getPaymentService(String type) {
switch (type) {
case "alipay":
return new AlipayService();
case "wechat":
return new WechatPayService();
default:
throw new IllegalArgumentException("不支持的支付类型:" + type);
}
}
}
4. 客户端使用
java
public class PaymentController {
public void checkout(String payType, BigDecimal amount) {
// 一行代码搞定,不用关心具体实现!
PaymentService service = PaymentFactory.getPaymentService(payType);
service.pay(amount);
}
}
使用口诀
业务代码别乱 new, 工厂帮你来创建。 需求变更不用怕, 改改配置就搞定!
进阶提示
💡 Spring 的 IOC 容器本质上就是一个超级工厂!
@Autowired自动注入,其实就是工厂帮你创建好了对象。
一、简单工厂模式(Simple Factory)
一句话理解:简单工厂 = 一个"万能工厂",根据你传的参数,帮你创建对应的对象。就像去奶茶店,你说"来杯珍珠奶茶",店员就给你做一杯。
核心思想
把对象的创建逻辑集中到一个工厂类里,客户端不用自己 new 对象。传入一个参数,工厂帮你决定创建什么。
为什么需要它?
❌ 没有工厂时,代码是这样的:
java
// 控制器里到处都是 new
if (type.equals("alipay")) {
return new AlipayService();
} else if (type.equals("wechat")) {
return new WechatPayService();
}
// 复制粘贴到 10 个控制器里...
// 需求变了要改 10 个地方 😭
✅ 有了简单工厂:
java
// 一行代码搞定
PaymentService service = PaymentFactory.create("alipay");
// 需求变了?改工厂一处即可!😎
代码结构图解
scss
┌─────────────────────────────────────────────────────────────┐
│ 客户端 (Client) │
│ "我要一个支付宝支付服务!" │
│ PaymentFactory.create("alipay") │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 简单工厂 (SimpleFactory) │
│ ┌─────────────────────────────────┐ │
│ │ createProduct(String type) │ │
│ │ ├─ if type="A" → new ProductA()│ │
│ │ ├─ if type="B" → new ProductB()│ │
│ │ └─ if type="C" → new ProductC()│ │
│ └─────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ 产品 A │ │ 产品 B │ │ 产品 C │
│ (ProductA) │ │ (ProductB) │ │ (ProductC) │
└────────────┘ └────────────┘ └────────────┘
核心代码示例
1. 定义产品接口
java
public interface PaymentService {
void pay(BigDecimal amount);
}
2. 具体产品实现
java
// 支付宝支付
public class AlipayService implements PaymentService {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
// 微信支付
public class WechatPayService implements PaymentService {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付:" + amount + "元");
}
}
3. 简单工厂类(核心!)
java
public class PaymentFactory {
// 私有构造,禁止外部 new
private PaymentFactory() {}
/**
* 根据类型创建对应的支付服务
* @param type 支付类型:alipay / wechat
* @return 对应的支付服务实例
*/
public static PaymentService create(String type) {
if ("alipay".equals(type)) {
return new AlipayService();
} else if ("wechat".equals(type)) {
return new WechatPayService();
}
throw new IllegalArgumentException("不支持的支付类型:" + type);
}
}
4. 客户端使用
java
public class OrderController {
public void checkout(String payType, BigDecimal amount) {
// 一行代码搞定!不用自己 new!
PaymentService service = PaymentFactory.create(payType);
service.pay(amount);
}
}
简单工厂的优缺点
| 优点 ✅ | 缺点 ❌ |
|---|---|
| 集中管理对象创建,代码复用 | 工厂类职责过重(所有创建逻辑都在这里) |
| 客户端解耦,不用关心具体实现 | 违反开闭原则(新增产品要修改工厂类) |
| 修改一处,全局生效 | if-else 会随着产品增多而膨胀 |
| 代码简洁,容易理解 | 产品多时,工厂类变得臃肿 |
适用场景
✅ 适合用:
- 产品种类少(2-5 种)
- 产品不经常新增
- 创建逻辑简单
- 快速开发,不想搞太复杂
❌ 不适合:
- 产品种类很多(10+ 种)
- 产品经常新增
- 需要严格遵循开闭原则
- 每个产品创建逻辑很复杂
使用口诀
产品不多变化少, 简单工厂刚刚好。 一行代码能创建, 省心省力没烦恼!
进阶:用 Map 优化简单工厂
当产品多了,if-else 很丑?用 Map 优化:
java
public class PaymentFactory {
private static final Map<String, Supplier<PaymentService>> MAP = new HashMap<>();
static {
MAP.put("alipay", AlipayService::new);
MAP.put("wechat", WechatPayService::new);
MAP.put("bank", BankCardService::new);
// 新增产品?这里加一行就行
}
public static PaymentService create(String type) {
Supplier<PaymentService> supplier = MAP.get(type);
if (supplier == null) {
throw new IllegalArgumentException("不支持的支付类型:" + type);
}
return supplier.get();
}
}
💡 优点:比 if-else 清爽,新增产品只需在 static 块加一行
二、工厂方法模式(Factory Method)
一句话理解:工厂方法模式 = "专人做专事",每种产品都有自己的专属工厂,不再是一个工厂包办所有!
核心思想
一个工厂只负责一种产品。把简单工厂的"大杂烩"拆成"专业档口"。
和简单工厂的区别
| 模式 | 比喻 | 特点 |
|---|---|---|
| 简单工厂 | 一家餐厅厨师啥都会 🍳 | 一个工厂创建所有,if-else 越来越多 |
| 工厂方法 | 美食城各档口专做 🍜🍕🍣 | 每个产品有专属工厂,扩展方便职责清晰 |
生活类比
❌ 简单工厂模式:
你来到"万能消息中心"
- 你说:"发个短信" → 它帮你发
- 你说:"发个邮件" → 它帮你发
(一个工厂类里写满 if-else,越来越臃肿...)
✅ 工厂方法模式:
你来到"消息美食城"
- 想发短信 → 去【短信工厂】📱
- 想发邮件 → 去【邮件工厂】📧
- 想发微信 → 去【微信工厂】💬
(每个工厂只干一件事,专业!)
代码结构图解
scss
┌─────────────────────────────────────────────────────────────────┐
│ 抽象工厂 (MessageFactory) │
│ ┌─────────────────┐ │
│ │ createSender() │ ← 抽象方法 │
│ │ 创建发送器 │ │
│ └─────────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ SmsFactory │ │ EmailFactory │ │ WechatFactory │
│ (短信工厂) │ │ (邮件工厂) │ │ (微信工厂) │
└───────┬────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ SmsSender │ │ EmailSender │ │ WechatSender │
│ (短信发送器) │ │ (邮件发送器) │ │ (微信发送器) │
└────────────────┘ └────────────────┘ └────────────────┘
核心代码示例
1. 定义消息发送器接口
java
public interface MessageSender {
void send(String to, String content);
}
2. 具体发送器实现
java
// 短信发送器 📱
public class SmsSender implements MessageSender {
@Override
public void send(String to, String content) {
System.out.println("【短信】发送至:" + to + ",内容:" + content);
}
}
// 邮件发送器 📧
public class EmailSender implements MessageSender {
@Override
public void send(String to, String content) {
System.out.println("【邮件】发送至:" + to + ",内容:" + content);
}
}
// 微信发送器 💬
public class WechatSender implements MessageSender {
@Override
public void send(String to, String content) {
System.out.println("【微信】发送至:" + to + ",内容:" + content);
}
}
3. 抽象工厂
java
public abstract class MessageFactory {
// 抽象方法:子类必须实现
public abstract MessageSender createSender();
}
4. 具体工厂(每个产品一个工厂)
java
// 短信工厂 - 只生产短信发送器
public class SmsFactory extends MessageFactory {
@Override
public MessageSender createSender() {
return new SmsSender();
}
}
// 邮件工厂 - 只生产邮件发送器
public class EmailFactory extends MessageFactory {
@Override
public MessageSender createSender() {
return new EmailSender();
}
}
// 微信工厂 - 只生产微信发送器
public class WechatFactory extends MessageFactory {
@Override
public MessageSender createSender() {
return new WechatSender();
}
}
5. 客户端使用
java
public class NotificationService {
public void notifyUser(String channel, String user, String message) {
MessageFactory factory;
switch (channel) {
case "sms":
factory = new SmsFactory();
break;
case "email":
factory = new EmailFactory();
break;
case "wechat":
factory = new WechatFactory();
break;
default:
throw new IllegalArgumentException("不支持的消息渠道:" + channel);
}
MessageSender sender = factory.createSender();
sender.send(user, message);
}
}
为什么用工厂方法?
❌ 简单工厂的问题:
每加一种类型,工厂类就要改一次! 违反开闭原则,if-else 越来越多...
老板:再加个钉钉通知! 你:又要改工厂类... 😭
✅ 工厂方法的优势:
新增钉钉通知?简单!
- 新建 DingTalkSender 类
- 新建 DingTalkFactory 类
- 完事儿!不用改原有代码!
符合开闭原则:对扩展开放,对修改关闭!😎
使用口诀
简单工厂一人扛, 工厂方法分工忙。 新增产品不犯愁, 开个新店就搞定!
适用场景
| 适用 ✅ | 不适用 ❌ |
|---|---|
| 产品种类多且经常新增 | 只有 2-3 种产品且不常变 |
| 需要符合开闭原则 | → 简单工厂就够了 |
| 产品创建逻辑复杂且各不相同 |
进阶提示
💡 Spring 的
@Bean注解,本质上就是工厂方法! 你每天都在用工厂方法,只是你不知道!😏
三、抽象工厂模式(Abstract Factory)
一句话理解:抽象工厂 = "成套生产"的工厂,不是生产单个产品,而是生产一整套相关的产品家族!就像去宜家买家具,买一套完整的"北欧风"(沙发+餐桌+床,风格统一)。
核心思想
- 创建一整套对象(产品族)
- 保证同一工厂生产的所有产品风格一致,不会出现混搭!
和前面两种工厂的区别
| 模式 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 生产什么 | 单个产品 | 单个产品 | 一整套产品族 |
| 比喻 | 一家餐厅啥都做 | 美食城各档口 | 宜家成套家具 |
生活类比
❌ 没有抽象工厂:
你自己装修房子:
- 沙发买欧式的
- 餐桌买中式的
- 床买美式的
混搭得像个"四不像"... �
✅ 使用抽象工厂:
去宜家直接选风格:
- 选【北欧风工厂】→ 给你北欧风沙发+餐桌+床
- 选【日式风工厂】→ 给你日式风沙发+餐桌+床
风格统一,不会出错!😎
代码结构图解
scss
┌─────────────────────────────────────────────────────────────────┐
│ 抽象工厂 (UIFactory) │
│ ┌─────────────────────────────────────┐ │
│ │ createButton() → 创建按钮 │ │
│ │ createTextField() → 创建输入框 │ │
│ │ createCheckbox() → 创建复选框 │ │
│ └─────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌────────────────────┐ ┌────────────────────┐
│ WindowsFactory │ │ MacFactory │
│ (Windows风格) │ │ (Mac风格) │
└───────┬────────────┘ └───────┬────────────┘
│ │
┌──────┴──────┐ ┌──────┴──────┐
▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐
│Windows │ │ Windows │ │ Mac │ │ Mac │
│Button │ │TextField │ │ Button │ │TextField │
└────────┘ └──────────┘ └────────┘ └──────────┘
核心代码示例
1. 定义产品族接口
java
// 按钮接口
public interface Button {
void render();
}
// 输入框接口
public interface TextField {
void render();
}
// 复选框接口
public interface Checkbox {
void render();
}
2. 具体产品实现(Windows 风格)
java
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染 Windows 风格按钮 🪟");
}
}
public class WindowsTextField implements TextField {
@Override
public void render() {
System.out.println("渲染 Windows 风格输入框 🪟");
}
}
public class WindowsCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("渲染 Windows 风格复选框 🪟");
}
}
3. 具体产品实现(Mac 风格)
java
public class MacButton implements Button {
@Override
public void render() {
System.out.println("渲染 Mac 风格按钮 🍎");
}
}
public class MacTextField implements TextField {
@Override
public void render() {
System.out.println("渲染 Mac 风格输入框 🍎");
}
}
public class MacCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("渲染 Mac 风格复选框 🍎");
}
}
4. 抽象工厂
java
public interface UIFactory {
Button createButton();
TextField createTextField();
Checkbox createCheckbox();
}
5. 具体工厂
java
// Windows 风格工厂
public class WindowsFactory implements UIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
// Mac 风格工厂
public class MacFactory implements UIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
6. 客户端使用
java
public class Application {
private Button button;
private TextField textField;
private Checkbox checkbox;
public Application(UIFactory factory) {
button = factory.createButton();
textField = factory.createTextField();
checkbox = factory.createCheckbox();
}
public void renderUI() {
button.render();
textField.render();
checkbox.render();
}
public static void main(String[] args) {
// 根据系统选择工厂
String osName = System.getProperty("os.name").toLowerCase();
UIFactory factory;
if (osName.contains("mac")) {
factory = new MacFactory();
} else {
factory = new WindowsFactory();
}
Application app = new Application(factory);
app.renderUI();
}
}
抽象工厂的优缺点
| 优点 ✅ | 缺点 ❌ |
|---|---|
| 保证产品族的一致性(不会混搭) | 新增产品族容易,新增产品等级结构难 |
| 客户端与具体实现解耦 | 代码复杂度增加 |
| 符合开闭原则(扩展产品族) | 产品族很多时,类数量爆炸 |
| 易于切换整个产品系列 |
适用场景
| 适用 ✅ | 不适用 ❌ |
|---|---|
| 需要创建一整套相关的产品 | 只需要创建单个产品 |
| 产品族需要保持一致性 | 产品之间没有关联 |
| 需要支持多种主题/风格切换 | 产品经常变化 |
| GUI 主题切换、数据库切换等 |
使用口诀
成套生产不混搭, 抽象工厂来当家。 风格统一不出错, 切换主题一句话!
三种工厂模式对比总结
| 对比项 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 创建对象 | 单个产品 | 单个产品 | 产品族(多个相关产品) |
| 工厂数量 | 1 个 | 多个(每个产品一个) | 多个(每个产品族一个) |
| 扩展性 | 差(修改工厂类) | 好(新增工厂类) | 好(新增产品族) |
| 复杂度 | 低 | 中 | 高 |
| 适用场景 | 产品少且不常变 | 产品多且常新增 | 需要成套产品族 |
| 开闭原则 | ❌ 违反 | ✅ 符合 | ✅ 符合(扩展产品族) |
一句话总结
- 简单工厂:一个工厂包办所有,简单粗暴
- 工厂方法:专人专事,各司其职
- 抽象工厂:成套生产,风格统一
选择建议
| 场景 | 推荐模式 |
|---|---|
| 2-5 种产品,不常变 | 简单工厂 |
| 产品多,经常新增 | 工厂方法 |
| 需要一整套相关产品 | 抽象工厂 |
| 使用 Spring | 直接 @Autowired,工厂模式内置了! |
💡 最后提醒:设计模式是工具,不是教条。根据实际情况选择最合适的,不要为了用模式而用模式!
📌 写文不易,Bug 更不易。
如果这篇文章对你有帮助,可以搜一搜:空门技术栈
推荐阅读
这里分享:
- ✅ Java / Spring AI / 企业级项目实战
- ✅ Docker / RAG知识库 / 微服务踩坑
- ✅ Python、前端、AI应用落地
- ✅ 偶尔分享一些「头发保卫战」经验 😆
一个热爱技术、持续填坑的开发者, 陪你一起少踩坑,少加班,多写优雅代码。
