☰
Java工厂模式实战:从简单工厂到Spring DI应用
2026/10/14 8:54:21 网站建设 项目流程

1. 工厂模式:从基础到实战的深度解析

工厂模式作为Java设计模式中最常用的创建型模式,其核心价值在于解耦对象的创建与使用。想象一下你去餐厅点餐的场景——你只需要告诉服务员"我要一份牛排",而不需要关心牛排是哪个厨师做的、用什么火候煎的。工厂模式正是扮演了这个"服务员"的角色,让调用者专注于业务逻辑,而非对象创建的细节。

在实际开发中,我们通常会遇到两种主要的工厂模式实现:简单工厂(Simple Factory)和工厂方法(Factory Method)。这两种模式看似相似,但在设计理念和使用场景上有着本质区别。理解这些差异,对于写出既优雅又实用的代码至关重要。

2. 简单工厂模式:快速上手的实用方案

2.1 简单工厂的核心结构

简单工厂模式由一个工厂类和多个产品类组成。工厂类包含一个静态方法,根据输入参数决定创建哪种产品实例。这种模式最大的特点是简单直接,特别适合产品类型相对固定的场景。

让我们通过一个电商平台的支付系统案例来理解简单工厂。假设我们需要支持多种支付方式:

// 支付接口 interface Payment { void pay(double amount); } // 具体支付实现 class Alipay implements Payment { @Override public void pay(double amount) { System.out.println("使用支付宝支付:" + amount + "元"); } } class WechatPay implements Payment { @Override public void pay(double amount) { System.out.println("使用微信支付:" + amount + "元"); } } // 简单工厂 class PaymentFactory { public static Payment createPayment(String type) { switch (type.toLowerCase()) { case "alipay": return new Alipay(); case "wechat": return new WechatPay(); default: throw new IllegalArgumentException("不支持的支付类型"); } } }

2.2 简单工厂的适用场景

简单工厂特别适合以下场景:

  1. 对象创建逻辑相对简单
  2. 产品类型数量有限且不太可能频繁扩展
  3. 需要快速实现解耦的场景

提示:在JDK中,Calendar.getInstance()和NumberFormat.getInstance()都是简单工厂的典型应用。

2.3 简单工厂的局限性

虽然简单工厂易于理解和实现,但它有一个明显的缺点:违反开闭原则。当需要新增支付方式时,必须修改工厂类的代码。例如,要增加银联支付:

class UnionPay implements Payment { @Override public void pay(double amount) { System.out.println("使用银联支付:" + amount + "元"); } } // 必须修改工厂类 class PaymentFactory { public static Payment createPayment(String type) { switch (type.toLowerCase()) { // 原有case... case "union": return new UnionPay(); default: throw new IllegalArgumentException("不支持的支付类型"); } } }

这种修改方式在大型系统中会导致工厂类变得越来越臃肿,维护成本也随之增加。

3. 工厂方法模式:面向扩展的设计

3.1 工厂方法的核心思想

工厂方法模式通过引入抽象工厂接口,将具体产品的创建延迟到子类中实现。这种设计完美遵循了开闭原则——对扩展开放,对修改关闭。

继续以支付系统为例,我们重构为工厂方法模式:

// 抽象工厂 interface PaymentFactory { Payment createPayment(); } // 具体工厂 class AlipayFactory implements PaymentFactory { @Override public Payment createPayment() { return new Alipay(); } } class WechatPayFactory implements PaymentFactory { @Override public Payment createPayment() { return new WechatPay(); } }

3.2 工厂方法的优势

工厂方法模式的主要优势在于:

  1. 完全遵循开闭原则,新增支付方式只需添加新工厂类
  2. 客户端代码只依赖抽象工厂和抽象产品,耦合度更低
  3. 更适合框架设计,允许第三方扩展

例如,要新增银联支付,只需:

class UnionPayFactory implements PaymentFactory { @Override public Payment createPayment() { return new UnionPay(); } }

原有代码完全不需要修改,真正实现了"对扩展开放,对修改关闭"。

3.3 工厂方法的代价

虽然工厂方法提供了极好的扩展性,但这种优势是有代价的:

  1. 类数量激增:每个产品都需要对应的工厂类
  2. 系统复杂度提高:需要理解更多的抽象层次
  3. 增加了代码阅读和维护的难度

4. 现代Java开发中的工厂模式实践

4.1 Spring依赖注入:工厂模式的终极形态

在现代Java企业开发中,Spring框架的依赖注入(DI)机制实际上实现了工厂模式的终极形态。Spring容器本质上是一个超级工厂,负责创建和管理所有bean对象。

通过注解方式使用DI:

@Service public class OrderService { private final PaymentService paymentService; @Autowired public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } public void processOrder(Order order) { paymentService.processPayment(order.getAmount()); } }

Spring会自动处理所有对象的创建和依赖关系,开发者完全不需要关心具体的实现类。

4.2 静态工厂方法的巧妙应用

即使在Spring生态中,静态工厂方法仍然有其用武之地。例如,创建复杂对象或需要特殊初始化的场景:

public class ComplexObjectFactory { public static ComplexObject createComplexObject(String config) { ComplexObject obj = new ComplexObject(); // 复杂的初始化逻辑 obj.init(config); return obj; } } // 在Spring配置中使用 @Bean public ComplexObject complexObject() { return ComplexObjectFactory.createComplexObject("default"); }

4.3 工厂模式与策略模式的组合

在实际业务中,工厂模式常与策略模式配合使用,实现高度灵活的业务逻辑。例如,电商平台的不同促销策略:

// 策略接口 interface DiscountStrategy { double applyDiscount(double originalPrice); } // 具体策略 class SeasonalDiscount implements DiscountStrategy { @Override public double applyDiscount(double originalPrice) { return originalPrice * 0.8; } } // 策略工厂 class DiscountStrategyFactory { public static DiscountStrategy getStrategy(String type) { switch (type) { case "seasonal": return new SeasonalDiscount(); // 其他策略... default: return originalPrice -> originalPrice; } } }

这种组合可以大幅减少业务代码中的条件判断,使系统更加灵活和可维护。

5. 实战中的避坑指南

5.1 避免过度设计

工厂方法虽然优雅,但并非所有场景都需要。评估标准包括:

  1. 产品类型是否会频繁扩展
  2. 系统规模和维护周期
  3. 团队的技术水平

对于小型项目或固定业务,简单工厂可能更实用。

5.2 正确处理异常情况

工厂模式中需要特别注意错误处理:

public Payment createPayment(String type) { Objects.requireNonNull(type, "支付类型不能为null"); try { // 创建逻辑 } catch (Exception e) { throw new PaymentCreationException("创建支付实例失败", e); } }

5.3 性能考量

对于频繁创建的对象,可以考虑以下优化:

  1. 使用对象池
  2. 缓存常用实例
  3. 延迟初始化
class CachedPaymentFactory { private static final Map<String, Payment> cache = new ConcurrentHashMap<>(); public static Payment getPayment(String type) { return cache.computeIfAbsent(type, key -> { // 实际创建逻辑 }); } }

6. 设计模式的选择策略

在实际项目中选择工厂模式实现时,可以参考以下决策树:

  1. 是否使用Spring框架?

    • 是 → 优先使用依赖注入
    • 否 → 进入下一步
  2. 产品类型是否固定?

    • 是 → 简单工厂
    • 否 → 工厂方法
  3. 是否需要支持第三方扩展?

    • 是 → 工厂方法
    • 否 → 简单工厂

记住一个实用口诀:"能用注入就用注入,不能注入写静态方法,除非你在开发框架才考虑工厂方法"。

7. 高级应用场景

7.1 泛型工厂

Java泛型可以与工厂模式结合,创建类型安全的工厂:

interface GenericFactory<T> { T create(); } class StringFactory implements GenericFactory<String> { @Override public String create() { return new String(); } }

7.2 多态工厂

工厂本身也可以是多态的,实现更灵活的对象创建:

interface AbstractFactory { ProductA createProductA(); ProductB createProductB(); } class ConcreteFactory1 implements AbstractFactory { // 实现方法... }

7.3 依赖查找 vs 依赖注入

理解这两种方式的区别很重要:

  • 依赖查找:主动从工厂或容器获取对象
  • 依赖注入:被动接收依赖对象

现代Java开发更推荐使用依赖注入,因为它能实现更高的解耦度。

8. 测试策略

针对工厂模式的测试需要注意:

  1. 工厂类测试:验证是否能正确创建各种产品
  2. 产品类测试:独立于工厂测试产品功能
  3. 集成测试:验证工厂和产品的协作
@Test void testPaymentFactory() { Payment alipay = PaymentFactory.createPayment("alipay"); assertTrue(alipay instanceof Alipay); Payment wechat = PaymentFactory.createPayment("wechat"); assertTrue(wechat instanceof WechatPay); }

9. 性能优化技巧

  1. 使用枚举实现简单工厂:
enum PaymentType { ALIPAY { @Override public Payment create() { return new Alipay(); } }, WECHAT { @Override public Payment create() { return new WechatPay(); } }; public abstract Payment create(); }
  1. 预初始化常用实例

  2. 考虑使用享元模式共享不变部分

10. 与其他模式的协作

工厂模式常与其他模式配合使用:

  1. 单例模式:工厂本身可能是单例
  2. 原型模式:通过复制原型创建新对象
  3. 建造者模式:创建复杂对象

理解这些模式的协作关系,可以设计出更优雅的解决方案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询