Skip to content

03 工厂模式家族(简单工厂 + 工厂方法 + 抽象工厂)🏭

这三个模式都在解决“对象创建”问题,强相关,合并学习效率最高。


1. 模式定义

  • 简单工厂:通过一个工厂类,根据参数决定创建哪种对象。
  • 工厂方法:把创建逻辑下放到子类工厂,每个工厂只生产一种产品。
  • 抽象工厂:提供创建“一族相关产品”的接口,面向产品族。

一句话区分:

  • 创建 一个产品:简单工厂 / 工厂方法
  • 创建 一组配套产品:抽象工厂

2. 为什么不直接 new

直接 new 不是错,很多时候它就是最简单、最清晰的方案。

适合直接 new

  • 对象创建逻辑非常简单
  • 类型固定,短期不会扩展
  • 小项目或脚本型代码,过度抽象反而增加负担

适合引入工厂:

  • 创建逻辑复杂(参数校验、配置读取、对象组装)
  • 类型经常新增(如新增支付渠道、消息渠道)
  • 希望业务代码“只依赖接口,不依赖具体实现”

真实痛点对比:

  • 直接 new:新增一种类型时,业务代码里到处改 if-else
  • 工厂模式:新增类型时,主要新增类并扩展工厂,调用方改动更小

3. 适用场景

3.1 简单工厂

场景:根据类型创建支付处理器(微信、支付宝、银行卡)。

3.2 工厂方法

场景:插件化系统,不同模块自己决定创建哪种实现。

3.3 抽象工厂

场景:跨平台 UI(Windows 按钮+输入框,Mac 按钮+输入框)必须成套出现。


4. Java 实现

3.1 简单工厂

java
interface PayService {
    void pay();
}

class WechatPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}

class AlipayService implements PayService {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}

class PayServiceFactory {
    public static PayService create(String type) {
        if ("wechat".equalsIgnoreCase(type)) {
            return new WechatPayService();
        }
        if ("alipay".equalsIgnoreCase(type)) {
            return new AlipayService();
        }
        throw new IllegalArgumentException("不支持的支付类型: " + type);
    }
}
java
public class Demo1 {
    public static void main(String[] args) {
        PayService payService = PayServiceFactory.create("wechat");
        payService.pay();
    }
}

3.2 工厂方法

java
interface PayService {
    void pay();
}

class WechatPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}

class AlipayService implements PayService {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}

interface PayFactory {
    PayService createPayService();
}

class WechatPayFactory implements PayFactory {
    @Override
    public PayService createPayService() {
        return new WechatPayService();
    }
}

class AlipayFactory implements PayFactory {
    @Override
    public PayService createPayService() {
        return new AlipayService();
    }
}
java
public class Demo2 {
    public static void main(String[] args) {
        PayFactory factory = new WechatPayFactory();
        factory.createPayService().pay();
    }
}

3.3 抽象工厂

java
interface Button {
    void render();
}

interface Input {
    void render();
}

class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Windows 按钮");
    }
}

class WindowsInput implements Input {
    @Override
    public void render() {
        System.out.println("Windows 输入框");
    }
}

class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("Mac 按钮");
    }
}

class MacInput implements Input {
    @Override
    public void render() {
        System.out.println("Mac 输入框");
    }
}

interface UiFactory {
    Button createButton();
    Input createInput();
}

class WindowsUiFactory implements UiFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public Input createInput() {
        return new WindowsInput();
    }
}

class MacUiFactory implements UiFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public Input createInput() {
        return new MacInput();
    }
}
java
public class Demo3 {
    public static void main(String[] args) {
        UiFactory factory = new WindowsUiFactory();
        factory.createButton().render();
        factory.createInput().render();
    }
}

5. 优缺点

模式优点缺点适用建议
简单工厂上手快,代码集中工厂类容易膨胀,违反开闭原则小项目、类型变化少
工厂方法符合开闭原则,易扩展类数量增加业务扩展频繁、插件化
抽象工厂保证产品族一致性抽象层次更复杂多产品族、跨平台体系

6. 源码映射

5.1 JDK

  • Calendar.getInstance():工厂思想
  • DocumentBuilderFactory.newInstance():工厂方法风格

5.2 Spring

  • BeanFactory / FactoryBean:工厂思想落地
  • ApplicationContext:对象获取入口,屏蔽创建细节
flowchart LR
    A["业务代码"] --> B["BeanFactory / ApplicationContext"]
    B --> C["创建或获取 Bean"]
    C --> D["返回接口类型对象"]

7. 面试考点

6.1 简单工厂和工厂方法的区别

  • 简单工厂:一个工厂根据参数创建多种产品
  • 工厂方法:多个工厂分别创建各自产品

6.2 工厂方法和抽象工厂的区别

  • 工厂方法:关注一个产品等级结构
  • 抽象工厂:关注多个产品等级结构组成的产品族

6.3 什么时候不要用工厂模式

  • 对象创建极其简单且稳定,不会扩展
  • 过早抽象会增加复杂度(小项目可先直 new

8. 学习建议

建议顺序:

  1. 先掌握简单工厂(理解“创建与使用分离”)
  2. 再学工厂方法(理解开闭原则)
  3. 最后学抽象工厂(理解产品族)

9. 练习题

  1. 实现一个“消息推送工厂”(短信、邮件、站内信)并支持扩展新渠道。
  2. 用工厂方法重构 if-else 创建逻辑。
  3. 设计一个“主题 UI 抽象工厂”(深色主题 / 浅色主题)并输出成套组件。

10. 小结

  • 工厂模式家族的共同目标:把对象创建细节封装起来
  • 从简单工厂到抽象工厂,本质是抽象层次逐步提高。
  • 工程里不要机械套模式,优先考虑团队可维护性与业务变化频率。