Skip to content

工厂模式平时在项目里几乎天天碰(Spring 的 @BeanBeanFactory 本质就是工厂),但"简单工厂、工厂方法、抽象工厂"这三个词到底什么关系、什么时候用哪个,一直没有清晰地串起来。这篇按演进顺序理一遍,每级解决什么问题、又带来什么新问题。

一、解决什么问题

工厂模式解决的是 new 的硬编码耦合

java
// 写死具体类:想换成微信支付,就得改这行代码
Pay pay = new Alipay();

一旦代码里到处 new Alipay(),切换实现、增加渠道、统一初始化逻辑,全都要改源码。工厂模式把"创建对象的逻辑"从"使用对象的地方"抽出来,集中到一个地方管理。

核心思想一句话:不直接 new,而是问工厂要

二、演进:简单工厂 → 工厂方法 → 抽象工厂

v1 简单工厂(Simple Factory):一个工厂包办所有

java
public class PayFactory {
    public static Pay create(String type) {
        switch (type) {
            case "alipay":  return new Alipay();
            case "wechat":  return new WechatPay();
            default: throw new IllegalArgumentException("不支持的支付方式: " + type);
        }
    }
}

// 使用方
Pay pay = PayFactory.create("alipay");
pay.pay(100);

一个工厂类 + 一个静态方法,根据参数 switch 返回不同产品。优点:把创建逻辑集中了,使用方不再 new缺点:每加一种支付方式,就要改 switch——违反开闭原则(对修改不关闭)。产品一多,switch 越来越长。

v2 工厂方法(Factory Method):把"创建哪个产品"交给子类

解决简单工厂"加产品要改工厂"的问题——用一个抽象"创建者"(Creator)类定义骨架,把"创建哪个产品"的工厂方法留给子类决定:

java
// Creator 抽象类:业务方法里调用工厂方法
public abstract class PayService {
    public void pay(int amount) {
        Pay pay = createPay();     // 业务方法调用工厂方法
        pay.pay(amount);
    }
    protected abstract Pay createPay();   // 工厂方法:子类决定创建哪个产品
}

// 子类决定产品:加一种支付 = 加一个子类,不改已有代码
public class AlipayService extends PayService {
    protected Pay createPay() { return new Alipay(); }
}
public class WechatService extends PayService {
    protected Pay createPay() { return new WechatPay(); }
}

// 使用方:换支付方式 = 换一个 Creator 子类
PayService service = new AlipayService();
service.pay(100);

工厂方法的核心:把"创建哪个产品"的决定权从使用方延迟到子类——createPay() 是工厂方法,AlipayService/WechatService 各自决定创建谁。加一种支付 = 新增一个子类,完全不改已有代码,符合开闭原则。代价:类数量增加,每加一个产品就多一个子类。注意工厂方法靠的是继承(换子类)来换产品。

v3 抽象工厂(Abstract Factory):一族相关产品

工厂方法一次只造一个产品。但当产品是成族出现的(比如一个支付渠道同时提供"支付"和"退款"两个能力),抽象工厂就来了:

java
public interface PayFactory {
    Pay createPay();        // 一族产品:支付 + 退款
    Refund createRefund();
}
public class AlipayFactory implements PayFactory {
    public Pay createPay() { return new AlipayPay(); }
    public Refund createRefund() { return new AlipayRefund(); }
}

抽象工厂保证"同一族产品之间的匹配",换一个工厂整族一起切——这是"产品成族"时的演进终点。完整讲透(产品族配套、和工厂方法的区别、UI 主题例子、JDBC 应用)看《抽象工厂模式》。

三、三种工厂对比

维度简单工厂工厂方法抽象工厂
工厂数量1 个每个产品 1 个(Creator 子类)每个产品族 1 个
创建对象一种(按参数分支)一种一族(多个相关)
变化方式switch继承(换子类)组合/实现(换工厂)
加产品switch(违反开闭)加子类(不改旧代码)加族(改接口)
复杂度
典型场景产品少、简单产品多、需扩展产品成族、需匹配

三种工厂演进:简单工厂一个工厂 switch 分支 → 工厂方法每个产品一个工厂 → 抽象工厂一族产品一个工厂

四、Spring 里的工厂

Spring 本身就是个巨型工厂,工厂模式贯穿其中:

  • BeanFactory / ApplicationContext:就是抽象工厂——getBean("name") 从容器里拿对象,而不是 new
  • @Bean 注解方法:就是工厂方法——方法返回的对象交给容器管理
java
@Configuration
public class PayConfig {
    @Bean
    public Pay alipay() {        // 工厂方法:@Bean 方法名就是产品名
        return new Alipay();
    }
}

这和单例模式也有关联——Spring 的 Bean 默认单例,工厂返回的往往是同一个实例(见《单例模式》)。

小结

  • 工厂模式解决 new 的硬编码耦合,把创建逻辑从使用处抽离
  • 演进线:简单工厂(一个工厂 switch,违反开闭)→ 工厂方法(每产品一工厂,符合开闭但类爆炸)→ 抽象工厂(一族产品一工厂,保证族内匹配)
  • 简单工厂适合产品少,工厂方法适合产品多需扩展,抽象工厂适合产品成族
  • Spring 的 BeanFactory@Bean 就是工厂模式的落地

下一步可以看同样高频的《策略模式》——它和工厂模式经常配合(工厂负责"创建哪个策略",策略负责"执行哪种算法"),两者放一起对比更容易分清。