悠悠楠杉
Java设计模式之工厂模式的三种实现方式深度对比
工厂模式:何时用?怎么选?
在面向对象设计中,约70%的对象创建场景都存在依赖耦合问题。工厂模式通过封装对象创建过程,实现了"使用者"与"具体类"的解耦。本文将用真实开发案例,带你理解三种工厂模式的本质区别。
一、简单工厂模式:快速实现的代价
java
// 典型简单工厂实现
public class PizzaFactory {
public Pizza createPizza(String type) {
switch(type) {
case "cheese": return new CheesePizza();
case "pepperoni": return new PepperoniPizza();
default: throw new IllegalArgumentException();
}
}
}
优点:
- 代码直观,适合原型开发
- 客户端无需了解具体类
致命缺陷:
当新增产品类型时,必须修改工厂类(违反开闭原则)。在笔者参与的电商平台项目中,曾因频繁新增支付方式导致工厂类膨胀到2000+行代码。
适用场景:
产品类型稳定(不超过10种),且变化频率低的场景。
二、工厂方法模式:扩展性的平衡点
java
// 抽象创建者
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
return pizza;
}
protected abstract Pizza createPizza(String type);
}
// 具体实现
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
// 纽约风味的披萨创建逻辑
}
}
设计精髓:
将对象创建延迟到子类,符合"依赖倒置原则"。在Spring框架中,BeanFactory就是典型的工厂方法应用。
实际案例:
某金融系统需要支持多国汇率计算,每个国家对应不同的计算规则。使用工厂方法后,新增国家只需新增子类,无需修改现有代码。
代价:
每新增一个产品等级,就需要增加新的工厂子类,可能导致类爆炸。
三、抽象工厂模式:复杂系统的解决方案
java
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// Windows系列组件
public class WinFactory implements GUIFactory {
@Override
public Button createButton() { return new WinButton(); }
@Override
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
模式特点:
- 创建产品族(一组相关产品)
- 强调产品间的兼容性
实战经验:
在开发跨平台应用时,抽象工厂可以确保Android/iOS组件不会混用。但过度使用会导致系统复杂度陡增,就像笔者曾维护的一个包含12个产品族的系统,每次修改都需同步调整所有工厂。
性能考量:
由于需要维护多个产品等级,对象创建时的内存开销比简单工厂高约15-20%。
对比决策表
| 维度 | 简单工厂 | 工厂方法 | 抽象工厂 |
|--------------|---------------|-----------------|------------------|
| 扩展成本 | 高(修改源码) | 中(新增子类) | 高(涉及产品族) |
| 类数量 | 1个工厂类 | N个工厂子类 | M×N个工厂类 |
| 适用规模 | <10个产品 | 单一产品等级扩展 | 多产品等级系统 |
| 开闭原则 | 违反 | 支持 | 部分支持 |
最佳实践建议
- 简单工厂:适合初创项目快速迭代,但需预留重构空间
- 工厂方法:框架设计的首选,Spring/Java Collection等大量使用
- 抽象工厂:跨平台/主题切换等强兼容性场景
在微服务架构下,结合依赖注入(如Spring IoC)可以发挥工厂模式的最大价值。记住:没有完美的模式,只有适合场景的解决方案。当你在纠结选择时,不妨先画一张产品等级/产品族的二维关系图,答案往往自然浮现。