1. 工厂方法模式的核心价值与应用场景
工厂方法模式作为创建型设计模式的代表,本质上解决的是对象实例化过程中的复杂性问题。在传统面向对象编程中,我们通常通过new关键字直接创建对象,但这种方式存在两个显著缺陷:一是客户端代码与具体实现类强耦合,二是当对象创建逻辑复杂时会导致代码重复。
我在实际开发中遇到过这样一个典型案例:某电商系统需要支持多种支付方式(支付宝、微信、银联等),初期采用简单工厂实现。但随着国际业务扩展,需要新增PayPal、Stripe等支付方式时,发现每次新增都需要修改工厂类,违反了开闭原则。这正是工厂方法模式的用武之地。
工厂方法模式通过定义创建对象的接口,但将具体实例化工作推迟到子类实现,完美解决了上述问题。其核心结构包含:
- Product(抽象产品):定义产品的接口
- ConcreteProduct(具体产品):实现产品接口的具体类
- Creator(抽象工厂):声明工厂方法
- ConcreteCreator(具体工厂):实现工厂方法
这种模式特别适用于以下场景:
- 一个类无法预知它需要创建的对象类别
- 一个类希望由其子类来指定所创建的对象
- 需要灵活扩展产品族时
提示:不要将工厂方法模式与简单工厂混淆。简单工厂把创建逻辑集中在一个类中,而工厂方法将创建职责分散到各个子类,更符合单一职责原则。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Java生态中的工厂方法模式实现
在Java标准库中,最经典的工厂方法模式应用是java.util.Collection接口的iterator()方法。这个方法就是典型的工厂方法,ArrayList、LinkedList等具体集合类各自实现自己的迭代器创建逻辑。
Spring框架更是将工厂方法模式运用得淋漓尽致。以BeanFactory为例:
java复制public interface BeanFactory {
Object getBean(String name) throws BeansException;
// 其他方法...
}
这里的getBean()就是工厂方法,而它的各种实现类如DefaultListableBeanFactory、XmlBeanFactory等负责具体Bean的创建。这种设计使得Spring可以支持多种配置方式(XML、注解、JavaConfig)而不需要修改客户端代码。
在自定义实现时,标准的工厂方法模式代码结构如下:
java复制// 抽象产品
interface Payment {
void pay(BigDecimal amount);
}
// 具体产品
class Alipay implements Payment {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付:" + amount);
}
}
// 抽象工厂
interface PaymentFactory {
Payment createPayment();
}
// 具体工厂
class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new Alipay();
}
}
这种实现方式虽然标准,但在实际Spring项目中,我们通常会结合Spring的DI特性进行优化:
java复制@Service
public class PaymentService {
private final Map<String, PaymentFactory> factories;
@Autowired
public PaymentService(List<PaymentFactory> factories) {
this.factories = factories.stream()
.collect(Collectors.toMap(
f -> f.getClass().getAnnotation(PaymentType.class).value(),
Function.identity()
));
}
public void pay(String type, BigDecimal amount) {
Payment payment = factories.get(type).createPayment();
payment.pay(amount);
}
}
3. Spring框架中的高级应用技巧
现代Spring项目通常会结合工厂方法模式与其他Spring特性实现更优雅的设计。以下是几种典型应用方式:
3.1 结合@Conditional的条件化Bean创建
Spring Boot的自动配置大量使用了这种技术:
java复制@Configuration
public class MyAutoConfiguration {
@Bean
@ConditionalOnClass(name = "com.example.ThirdPartyClass")
public ThirdPartyService thirdPartyService() {
return new ThirdPartyServiceImpl();
}
}
这种模式本质上是工厂方法模式的变体,根据运行时条件决定创建哪个具体的Bean实现。
3.2 使用@Configuration和@Bean的显式工厂
对于复杂对象的创建,可以创建专门的配置类作为工厂:
java复制@Configuration
public class ComplexObjectFactory {
@Bean
@Scope("prototype")
public ComplexObject complexObject(DepA a, DepB b) {
ComplexObject obj = new ComplexObject();
obj.setA(a);
obj.setB(b);
// 复杂的初始化逻辑
return obj;
}
}
3.3 基于枚举的工厂方法实现
对于固定类型的工厂,枚举方式非常简洁:
java复制public enum PaymentMethod {
ALIPAY {
@Override
public Payment create() {
return new Alipay();
}
},
WECHAT {
@Override
public Payment create() {
return new WechatPay();
}
};
public abstract Payment create();
}
注意:在Spring环境中使用枚举工厂时,要注意Bean的生命周期管理。枚举实例是JVM单例,如果Payment实现类有状态且需要原型作用域,这种方案就不适用。
4. 复杂业务场景下的模式变体
在实际企业级开发中,纯标准的工厂方法模式可能不够灵活,我们需要根据具体业务需求进行变通。
4.1 带参数的工厂方法
有时产品的创建需要依赖动态参数:
java复制public interface ReportGeneratorFactory {
ReportGenerator createGenerator(ReportType type, LocalDate period);
}
@Service
public class PdfReportGeneratorFactory implements ReportGeneratorFactory {
@Override
public ReportGenerator createGenerator(ReportType type, LocalDate period) {
PdfReportGenerator generator = new PdfReportGenerator();
generator.setTemplate(findTemplate(type, period));
return generator;
}
}
4.2 缓存和对象池优化
对于创建成本高的对象,可以结合对象池:
java复制public class DatabaseConnectionFactory {
private final Map<String, ConnectionPool> pools = new ConcurrentHashMap<>();
public Connection getConnection(String datasource) {
ConnectionPool pool = pools.computeIfAbsent(datasource,
ds -> createPool(ds));
return pool.borrowObject();
}
}
4.3 异步工厂方法
在响应式编程中,可能需要异步创建对象:
java复制public interface AsyncServiceFactory {
Mono<MyService> createService(ServiceConfig config);
}
public class DefaultAsyncServiceFactory implements AsyncServiceFactory {
@Override
public Mono<MyService> createService(ServiceConfig config) {
return Mono.fromCallable(() -> {
MyService service = new MyService();
service.init(config); // 耗时的初始化
return service;
}).subscribeOn(Schedulers.boundedElastic());
}
}
5. 性能优化与常见陷阱
虽然工厂方法模式提供了很好的灵活性,但不当使用也会带来问题。
5.1 对象创建性能考量
频繁创建复杂对象可能影响性能。解决方案包括:
- 对无状态对象使用享元模式
- 对昂贵对象使用对象池
- 尽可能重用已创建实例
5.2 循环依赖问题
在Spring环境中,工厂方法可能引发循环依赖:
java复制@Component
public class ServiceA {
private final ServiceBFactory bFactory;
public ServiceA(ServiceBFactory bFactory) {
this.bFactory = bFactory;
}
}
@Component
public class ServiceBFactory {
private final ServiceA serviceA;
public ServiceBFactory(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
解决方法:
- 使用@Lazy延迟初始化
- 改为setter注入
- 重构设计,消除循环依赖
5.3 测试策略
工厂类的测试要点:
java复制public class PaymentFactoryTest {
@Test
public void testAlipayFactory() {
PaymentFactory factory = new AlipayFactory();
Payment payment = factory.createPayment();
assertThat(payment).isInstanceOf(Alipay.class);
// 验证支付对象初始状态
assertThat(payment.isInitialized()).isTrue();
}
@SpringBootTest
public static class SpringIntegrationTest {
@Autowired
private Map<String, PaymentFactory> factories;
@Test
public void testAllFactoriesRegistered() {
assertThat(factories).containsKeys("alipay", "wechat");
}
}
}
6. 现代Java特性下的演进
随着Java语言发展,工厂方法模式也有新的实现方式。
6.1 利用Lambda简化工厂
Java 8以后,函数式接口可以简化工厂实现:
java复制public class PaymentFactory {
private final Map<String, Supplier<Payment>> creators = new HashMap<>();
public PaymentFactory() {
creators.put("alipay", Alipay::new);
creators.put("wechat", WechatPay::new);
}
public Payment create(String type) {
return creators.get(type).get();
}
}
6.2 密封类与模式匹配
Java 17的密封类特性可以让工厂方法更安全:
java复制public sealed interface Payment permits Alipay, WechatPay {
void pay(BigDecimal amount);
}
public final class Alipay implements Payment { /*...*/ }
public final class WechatPay implements Payment { /*...*/ }
public class PaymentFactory {
public Payment create(String type) {
return switch (type) {
case "alipay" -> new Alipay();
case "wechat" -> new WechatPay();
default -> throw new IllegalArgumentException();
};
}
}
6.3 记录类(Record)作为产品
对于不可变的产品对象,使用Record更简洁:
java复制public record ApiResponse(int code, String body) {}
public interface ResponseFactory {
ApiResponse create(int code, String body);
}
public class DefaultResponseFactory implements ResponseFactory {
@Override
public ApiResponse create(int code, String body) {
return new ApiResponse(code, body);
}
}
7. 设计模式组合应用
工厂方法模式很少单独使用,通常与其他模式配合。
7.1 结合策略模式
典型的支付处理场景:
java复制public interface PaymentStrategy {
void execute(BigDecimal amount);
}
public class PaymentProcessor {
private final PaymentStrategyFactory factory;
public void process(String type, BigDecimal amount) {
PaymentStrategy strategy = factory.create(type);
strategy.execute(amount);
}
}
7.2 结合装饰器模式
为产品动态添加功能:
java复制public interface DataProcessor {
void process(Data data);
}
public class LoggingProcessorFactory implements DataProcessorFactory {
private final DataProcessorFactory delegate;
@Override
public DataProcessor create() {
return new LoggingDecorator(delegate.create());
}
}
class LoggingDecorator implements DataProcessor {
private final DataProcessor wrapped;
public void process(Data data) {
logBefore();
wrapped.process(data);
logAfter();
}
}
7.3 结合模板方法模式
在抽象工厂中定义创建流程:
java复制public abstract class DocumentFactory {
public final Document createDocument() {
Document doc = createEmptyDocument();
addDefaultSections(doc);
customizeDocument(doc);
return doc;
}
protected abstract Document createEmptyDocument();
protected void customizeDocument(Document doc) {}
}
8. 领域驱动设计中的工厂
在DDD中,工厂方法模式有特殊应用。
8.1 聚合根工厂
确保聚合根的创建满足不变条件:
java复制public class OrderFactory {
public Order createOrder(Customer customer, List<OrderItem> items) {
if (items.isEmpty()) {
throw new IllegalArgumentException();
}
Order order = new Order();
order.setCustomer(customer);
items.forEach(order::addItem);
order.calculateTotal();
return order;
}
}
8.2 值对象工厂
对复杂值对象提供创建方法:
java复制public class AddressFactory {
public Address create(String country, String postalCode) {
// 验证邮编格式是否符合国家规范
validatePostalCode(country, postalCode);
return new Address(country, postalCode);
}
}
8.3 领域服务中的工厂
将创建逻辑封装在领域服务中:
java复制@Service
@Transactional
public class OrderProcessingService {
private final OrderFactory orderFactory;
public Order createOrderFromCart(ShoppingCart cart) {
List<OrderItem> items = convertCartItems(cart);
return orderFactory.createOrder(cart.getCustomer(), items);
}
}
9. 测试驱动开发实践
采用TDD方式开发工厂类时,建议从使用端开始设计。
9.1 测试先行案例
首先定义期望的工厂行为:
java复制public class PaymentFactoryTest {
@Test
public void createsAlipayInstance() {
PaymentFactory factory = new AlipayFactory();
Payment payment = factory.createPayment();
assertThat(payment).isInstanceOf(Alipay.class);
}
}
9.2 模拟工厂测试
测试依赖工厂的客户端代码:
java复制public class CheckoutServiceTest {
@Test
public void usesCorrectPaymentType() {
Payment mockPayment = mock(Payment.class);
PaymentFactory mockFactory = when(mock(PaymentFactory.class)
.createPayment()).thenReturn(mockPayment);
CheckoutService service = new CheckoutService(mockFactory);
service.checkout(100, "alipay");
verify(mockPayment).pay(100);
}
}
9.3 集成测试方案
验证工厂与真实实现的集成:
java复制@SpringBootTest
public class PaymentFactoryIntegrationTest {
@Autowired
private Map<String, PaymentFactory> factories;
@Test
public void allFactoriesProduceWorkingPayments() {
factories.forEach((type, factory) -> {
Payment payment = factory.createPayment();
assertThatNoException().isThrownBy(
() -> payment.pay(BigDecimal.ONE));
});
}
}
10. 复杂项目中的最佳实践
在大型项目中应用工厂方法模式时,需要注意以下要点:
-
工厂接口设计原则
- 保持工厂方法单一职责
- 考虑添加validate()方法验证创建前提条件
- 为工厂方法添加JavaDoc说明创建对象的生命周期管理责任
-
包结构组织建议
code复制com.example.payment ├── model │ ├── Payment.java │ ├── Alipay.java │ └── WechatPay.java ├── factory │ ├── PaymentFactory.java │ ├── AlipayFactory.java │ └── WechatFactory.java └── service └── PaymentService.java -
文档规范要求
- 在工厂接口中明确线程安全要求
- 记录每个具体工厂创建的对象特性
- 说明异常处理策略
-
性能监控指标
- 工厂方法调用频率
- 对象创建耗时
- 创建失败率
-
扩展性设计
- 考虑添加工厂注册机制
- 支持动态加载新工厂实现
- 提供工厂配置选项
在实际项目中,我通常会创建一个BaseFactoryTemplate抽象类,提供一些公共能力:
java复制public abstract class BaseFactory<T> {
private final Map<String, T> cache = new ConcurrentHashMap<>();
protected abstract T createInstance(String key);
public T get(String key) {
return cache.computeIfAbsent(key, this::createInstance);
}
protected void validateKey(String key) {
if (key == null || key.isBlank()) {
throw new IllegalArgumentException();
}
}
}
这种模板结合了工厂方法模式和缓存优化,在需要频繁创建同类对象的场景下特别有用,比如配置解析、插件加载等。关键在于平衡灵活性和性能,既保持扩展性又不失效率。
