别再 new 满天飞了!一文搞懂工厂模式,程序员终于不用手搓对象了 😆

工厂模式(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 越来越多...

老板:再加个钉钉通知! 你:又要改工厂类... 😭

✅ 工厂方法的优势:

新增钉钉通知?简单!

  1. 新建 DingTalkSender 类
  2. 新建 DingTalkFactory 类
  3. 完事儿!不用改原有代码!

符合开闭原则:对扩展开放,对修改关闭!😎


使用口诀

简单工厂一人扛, 工厂方法分工忙。 新增产品不犯愁, 开个新店就搞定!


适用场景

适用 ✅ 不适用 ❌
产品种类多且经常新增 只有 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 更不易。

如果这篇文章对你有帮助,可以搜一搜:空门技术栈

推荐阅读

  1. 策略模式:告别 if-else 地狱,让代码优雅到飞起
  2. 写 Java 别只会 new:工厂模式,才是对象界的正规军!
  3. 别让 AI 乱操作!Spring AI Alibaba 人工介入(Human-in-the-Loop)实战

这里分享:

  • ✅ Java / Spring AI / 企业级项目实战
  • ✅ Docker / RAG知识库 / 微服务踩坑
  • ✅ Python、前端、AI应用落地
  • ✅ 偶尔分享一些「头发保卫战」经验 😆

一个热爱技术、持续填坑的开发者, 陪你一起少踩坑,少加班,多写优雅代码。

相关推荐
阿丰资源1 小时前
基于SpringBoot的企业客户管理系统(附源码)
java·spring boot·后端
两年半的个人练习生^_^1 小时前
SpringBoot 项目使用 Jasypt 实现配置文件敏感信息加密
java·spring boot·后端
JAVA学习通2 小时前
开云集致 Java开发 实习 一面
java·开发语言
阿旭超级学得完2 小时前
C++11(初始化)
java·开发语言·数据结构·c++·算法
一只大袋鼠2 小时前
SpringMVC全局异常处理
java·开发语言·springmvc·javaweb
多加点辣也没关系2 小时前
设计模式-抽象工厂模式
java·设计模式·抽象工厂模式
不知名的老吴2 小时前
C++中emplace函数的不适场景总结(一)
java·开发语言·c++
LJianK12 小时前
线程安全、线程同步、竞态条件
java·开发语言
Ting-yu2 小时前
SpringCloud快速入门(3)---- 创建微服务项目
java·spring cloud·微服务