Appearance
工厂模式怎么选:简单工厂、工厂方法、抽象工厂的边界
很多项目刚开始写的时候,对象创建都很直接:
java
PayService payService = new WechatPayService();这样写并没有错,但当创建逻辑越来越复杂、实现类越来越多时,业务代码就会开始被 new 污染。
这时候,工厂模式才真正有价值。
先说结论
如果只记一个实用判断:
- 简单工厂:实现类不多,想集中创建逻辑
- 工厂方法:不同产品的创建过程差异变大
- 抽象工厂:一组相关产品需要一起创建
不要为了“用模式而用模式”,关键还是看对象创建有没有成为变化点。
一、为什么需要工厂模式
如果对象创建逻辑分散在业务代码里,后面通常会遇到这些问题:
- 业务类知道太多实现细节
- 实现类一变,调用方到处要改
- 创建过程带配置、校验、初始化时,代码会越来越乱
工厂模式的本质,是把“创建对象”这件事从业务流程里拆出去。
二、简单工厂:先把创建逻辑集中起来
简单工厂最直观的做法,就是由一个工厂类统一负责创建对象。
java
public interface Sender {
void send();
}
public class MailSender implements Sender {
@Override
public void send() {
System.out.println("mail");
}
}
public class SmsSender implements Sender {
@Override
public void send() {
System.out.println("sms");
}
}
public class SenderFactory {
public Sender create(String type) {
if ("mail".equals(type)) {
return new MailSender();
}
if ("sms".equals(type)) {
return new SmsSender();
}
throw new IllegalArgumentException("unsupported type: " + type);
}
}简单工厂适合什么时候用
- 产品类型有限
- 创建逻辑比较简单
- 想先把散落的
new收口
它的边界在哪里
最大问题是:
- 新增产品时,工厂类本身要改
也就是说,它违背了“对扩展开放、对修改关闭”的方向。
另外,很多旧笔记里会用字符串来区分类型,这种写法能跑,但不够稳,至少应该:
- 用枚举代替裸字符串
- 非法类型时主动抛异常
三、工厂方法:让每种产品有自己的工厂
当不同产品的创建流程已经明显不一样时,继续把所有逻辑塞进一个工厂类里,就会越来越臃肿。
这时可以考虑工厂方法。
java
public interface SenderFactory {
Sender create();
}
public class MailSenderFactory implements SenderFactory {
@Override
public Sender create() {
return new MailSender();
}
}
public class SmsSenderFactory implements SenderFactory {
@Override
public Sender create() {
return new SmsSender();
}
}它解决了什么问题
- 新增产品时,通常只要新增实现类和对应工厂
- 单个工厂职责更清晰
它的代价是什么
- 类会明显变多
- 如果产品规模不大,可能显得有点重
所以工厂方法不是“永远比简单工厂高级”,而是更适合变化已经变复杂的时候。
四、抽象工厂:一次创建一整套相关产品
如果你的系统不是创建一个对象,而是创建“同一风格的一整套对象”,抽象工厂才有意义。
例如:
- 不同数据库驱动下的一组连接对象
- 不同 UI 风格下的一组组件
- 不同支付渠道下的一组适配对象
抽象工厂更强调的是:
- 一组相关对象要成套出现
这已经不是“创建单个产品”的问题,而是“产品族”的问题。
五、工程里怎么选更稳
可以用一个很实用的判断顺序:
1. 先问对象创建是否已经成了痛点
如果创建逻辑还很简单,直接 new 并不一定有问题。
2. 如果只是想把创建逻辑集中起来
先用简单工厂就够了。
3. 如果不同产品的创建流程差异越来越大
考虑工厂方法。
4. 如果你要管理的是一组有关联的产品
再考虑抽象工厂。
六、Java 和 Spring 里哪些地方能看到工厂思想
工厂模式并不只存在于设计模式教材里。
在 Java 和 Spring 里,工厂思想非常常见:
BeanFactoryFactoryBean- 各种 Builder / Client 的创建器
很多框架并不是完整照搬某一种模式,而是把工厂思想揉进了自己的设计里。
七、几个容易踩的坑
1. 用字符串区分所有产品
这种写法很常见,但扩展性和可维护性都一般。
2. 工厂类里又开始写业务逻辑
工厂应该只关心创建,不该承担过多业务判断。
3. 只有两个实现类也上复杂抽象
抽象不是越早越好,而是变化真的出现时再做更值。
一句话总结
工厂模式的重点,不是背“有三种工厂”,而是判断对象创建是不是已经成了变化点。
变化不大时,简单工厂足够;变化越来越复杂时,再考虑工厂方法和抽象工厂。