1. 工厂模式到底解决了什么问题
我第一次接触工厂模式是在一个电商系统的支付模块重构中。当时系统需要对接支付宝、微信支付、银联等多家支付渠道,最初的代码是这样的:
java复制public class PaymentService {
public void pay(String type, BigDecimal amount) {
if ("alipay".equals(type)) {
AlipayPayment alipay = new AlipayPayment();
alipay.pay(amount);
} else if ("wechat".equals(type)) {
WechatPayment wechat = new WechatPayment();
wechat.pay(amount);
} else if ("unionpay".equals(type)) {
UnionPayment union = new UnionPayment();
union.pay(amount);
}
// 每新增一个支付渠道就要修改这里
}
}
这段代码的问题非常典型:
- 违反开闭原则(OCP) - 每次新增支付渠道都要修改PaymentService
- 创建逻辑与业务逻辑耦合 - pay()方法既负责对象创建又负责支付业务
- 难以单元测试 - 各种new操作使得无法mock支付实现
工厂模式的核心价值就在于将对象的创建与使用分离。就像你去餐厅点餐,不需要知道菜品如何制作(创建),只需告诉服务员要什么(使用)。这种分离带来了三大优势:
- 扩展性:新增产品类型时无需修改客户端代码
- 可维护性:创建逻辑集中管理,修改只需调整工厂类
- 可测试性:可以轻松替换为mock对象进行测试
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三种工厂模式的本质区别
2.1 简单工厂(静态工厂)
简单工厂是最容易理解的形式,通过一个静态方法封装对象创建:
java复制public class PaymentFactory {
public static Payment createPayment(String type) {
switch(type) {
case "alipay": return new AlipayPayment();
case "wechat": return new WechatPayment();
default: throw new IllegalArgumentException("未知支付类型");
}
}
}
适用场景:
- 产品类型较少且稳定
- 不需要继承体系(工厂类不需要子类化)
实际案例:JDK中的Calendar.getInstance()就是典型的简单工厂
2.2 工厂方法模式
当产品类型可能扩展时,应该使用工厂方法模式。它定义了一个创建对象的接口,但让子类决定实例化哪个类:
java复制// 抽象工厂
public interface PaymentFactory {
Payment createPayment();
}
// 具体工厂
public class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new AlipayPayment();
}
}
设计要点:
- 每个具体产品对应一个具体工厂
- 新增支付类型只需新增工厂类,无需修改现有代码
- 符合"开闭原则"(对扩展开放,对修改关闭)
Spring中的应用:BeanFactory就是工厂方法的典型实现
2.3 抽象工厂模式
抽象工厂用于创建产品族(一组相关或依赖的对象)。比如不同风格的UI组件:
java复制// 抽象工厂
public interface GUIFactory {
Button createButton();
Dialog createDialog();
}
// 具体工厂
public class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Dialog createDialog() { return new MacDialog(); }
}
与工厂方法的区别:
- 工厂方法:创建单一产品
- 抽象工厂:创建多个相关产品
经典案例:JDBC中的Connection就是抽象工厂,可以创建Statement、PreparedStatement等产品
3. 工厂模式的进阶实践技巧
3.1 依赖注入与工厂模式
现代框架通常结合DI容器实现更灵活的工厂:
java复制// 使用Spring的FactoryBean
public class PaymentFactoryBean implements FactoryBean<Payment> {
private String type;
@Override
public Payment getObject() {
return PaymentFactory.createPayment(type);
}
// setter for type...
}
优势:
- 配置化:支付类型可以通过配置文件指定
- 生命周期管理:由容器管理对象的创建和销毁
3.2 使用枚举消除条件判断
避免if-else的优雅实现:
java复制public enum PaymentType {
ALIPAY(AlipayPayment::new),
WECHAT(WechatPayment::new);
private final Supplier<Payment> constructor;
PaymentType(Supplier<Payment> constructor) {
this.constructor = constructor;
}
public Payment create() {
return constructor.get();
}
}
3.3 对象池模式优化
对于创建成本高的对象(如数据库连接),可以扩展工厂实现对象池:
java复制public class ConnectionPoolFactory {
private static Queue<Connection> pool = new ConcurrentLinkedQueue<>();
public static Connection getConnection() {
Connection conn = pool.poll();
return conn != null ? conn : createNewConnection();
}
public static void release(Connection conn) {
pool.offer(conn);
}
}
4. 工厂模式的典型误用与规避
4.1 过度设计警告
反面案例:为只有2-3种简单对象的情况引入抽象工厂
判断标准:
- 如果产品类型基本固定,使用简单工厂即可
- 只有当预计会有多个产品系列时才需要抽象工厂
4.2 循环依赖问题
当产品依赖工厂,工厂又依赖产品时:
java复制// 错误示例
public class ProductA {
private Factory factory; // 产品依赖工厂
}
public class FactoryA {
public Product create() {
return new ProductA(this); // 工厂又需要传入自身
}
}
解决方案:
- 使用setter注入代替构造器注入
- 引入第三方协调者(如Spring容器)
4.3 测试陷阱
直接使用new创建对象会导致测试困难:
java复制// 难以测试的代码
public class OrderService {
public void checkout() {
Payment payment = new AlipayPayment(); // 无法mock
payment.pay();
}
}
正确做法:
java复制public class OrderService {
private PaymentFactory factory;
public void checkout() {
Payment payment = factory.createPayment(); // 可注入mock工厂
payment.pay();
}
}
5. 现代编程语言中的工厂模式演进
5.1 Java中的静态工厂方法
Effective Java第一条就推荐使用静态工厂方法代替构造器:
java复制public class User {
private User() {}
// 静态工厂方法
public static User createWithEmail(String email) {
User user = new User();
user.setEmail(email);
return user;
}
}
优势包括:
- 方法名可以表达创建逻辑(如createWithEmail)
- 可以缓存实例(如Boolean.valueOf)
- 可以返回子类对象
5.2 Kotlin的伴生对象工厂
Kotlin提供了更优雅的实现方式:
kotlin复制class Payment private constructor(val type: String) {
companion object {
fun alipay(): Payment = Payment("alipay")
fun wechat(): Payment = Payment("wechat")
}
}
5.3 Go语言的工厂函数惯例
在Go中通常以New前缀表示工厂函数:
go复制func NewPayment(paymentType string) (Payment, error) {
switch paymentType {
case "alipay":
return &AlipayPayment{}, nil
default:
return nil, errors.New("unknown payment type")
}
}
6. 设计模式组合实践
6.1 工厂+策略模式
支付场景的完美组合:
java复制// 策略接口
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
// 工厂创建策略
public class PaymentStrategyFactory {
public PaymentStrategy create(String type) {
switch(type) {
case "alipay": return new AlipayStrategy();
case "wechat": return new WechatStrategy();
default: throw new IllegalArgumentException();
}
}
}
6.2 工厂+装饰器模式
带日志功能的支付创建:
java复制public class LoggingPaymentFactory implements PaymentFactory {
private PaymentFactory delegate;
public Payment createPayment() {
Payment payment = delegate.createPayment();
return new LoggingPaymentDecorator(payment);
}
}
6.3 工厂+原型模式
基于原型的高效创建:
java复制public class PrototypeFactory {
private Map<String, Payment> prototypes = new HashMap<>();
public Payment create(String type) {
Payment proto = prototypes.get(type);
return proto.clone();
}
}
工厂模式就像软件构建中的"生产车间",掌握它的核心在于理解:创建逻辑本身就是一种需要被抽象和封装的重要关注点。经过多个项目的实践,我发现合理使用工厂模式能使代码在面对变化时更加从容,这也是它历经数十年仍然被广泛使用的原因。
