工厂模式平时在项目里几乎天天碰(Spring 的 @Bean、BeanFactory 本质就是工厂),但"简单工厂、工厂方法、抽象工厂"这三个词到底什么关系、什么时候用哪个,一直没有清晰地串起来。这篇按演进顺序理一遍,每级解决什么问题、又带来什么新问题。
一、解决什么问题
工厂模式解决的是 new 的硬编码耦合。
// 写死具体类:想换成微信支付,就得改这行代码
Pay pay = new Alipay();一旦代码里到处 new Alipay(),切换实现、增加渠道、统一初始化逻辑,全都要改源码。工厂模式把"创建对象的逻辑"从"使用对象的地方"抽出来,集中到一个地方管理。
核心思想一句话:不直接 new,而是问工厂要。
二、演进:简单工厂 → 工厂方法 → 抽象工厂
v1 简单工厂(Simple Factory):一个工厂包办所有
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)类定义骨架,把"创建哪个产品"的工厂方法留给子类决定:
// 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):一族相关产品
工厂方法一次只造一个产品。但当产品是成族出现的(比如一个支付渠道同时提供"支付"和"退款"两个能力),抽象工厂就来了:
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(违反开闭) | 加子类(不改旧代码) | 加族(改接口) |
| 复杂度 | 低 | 中 | 高 |
| 典型场景 | 产品少、简单 | 产品多、需扩展 | 产品成族、需匹配 |
四、Spring 里的工厂
Spring 本身就是个巨型工厂,工厂模式贯穿其中:
BeanFactory/ApplicationContext:就是抽象工厂——getBean("name")从容器里拿对象,而不是new@Bean注解方法:就是工厂方法——方法返回的对象交给容器管理
@Configuration
public class PayConfig {
@Bean
public Pay alipay() { // 工厂方法:@Bean 方法名就是产品名
return new Alipay();
}
}这和单例模式也有关联——Spring 的 Bean 默认单例,工厂返回的往往是同一个实例(见《单例模式》)。
小结
- 工厂模式解决
new的硬编码耦合,把创建逻辑从使用处抽离 - 演进线:简单工厂(一个工厂
switch,违反开闭)→ 工厂方法(每产品一工厂,符合开闭但类爆炸)→ 抽象工厂(一族产品一工厂,保证族内匹配) - 简单工厂适合产品少,工厂方法适合产品多需扩展,抽象工厂适合产品成族
- Spring 的
BeanFactory、@Bean就是工厂模式的落地
下一步可以看同样高频的《策略模式》——它和工厂模式经常配合(工厂负责"创建哪个策略",策略负责"执行哪种算法"),两者放一起对比更容易分清。
