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):每个产品一个工厂

解决简单工厂"加产品要改工厂"的问题——把工厂也抽象成接口,每个产品配一个工厂类:

java
public interface PayFactory {
    Pay create();
}

public class AlipayFactory implements PayFactory {
    public Pay create() { return new Alipay(); }
}

public class WechatFactory implements PayFactory {
    public Pay create() { return new WechatPay(); }
}

// 使用方
PayFactory factory = new AlipayFactory();
Pay pay = factory.create();

现在加一种支付方式 = 新增一个产品类 + 新增一个工厂类,完全不改已有代码,符合开闭原则。代价:类爆炸——每加一个产品就多一个工厂类,产品多的时候类数量翻倍。所以工厂方法适合"产品种类固定、但要灵活扩展"的场景。

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(); }
}

// 使用方:换一个工厂,整套产品族一起换
PayFactory factory = new AlipayFactory();
Pay pay = factory.createPay();
Refund refund = factory.createRefund();

抽象工厂保证"同一族产品之间的匹配"——不会出现"支付宝的支付 + 微信的退款"这种错配。换渠道时,换一个工厂,整族产品一起切。

三、三种工厂对比

维度简单工厂工厂方法抽象工厂
工厂数量1 个每个产品 1 个每个产品族 1 个
创建对象一种(按参数分支)一种一族(多个相关)
加产品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 就是工厂模式的落地

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