35_Java设计模式之工厂模式
2026/6/14 15:55:00 网站建设 项目流程

Java设计模式之工厂模式

文章目录

  • Java设计模式之工厂模式
    • 前言
    • 一、简单工厂模式
    • 二、工厂方法模式
    • 三、抽象工厂模式
    • 四、三种工厂模式对比
    • 五、Spring中的工厂模式应用
    • 总结
    • ✅ 亮点总结
    • 适用场景
    • 扩展方向

前言

工厂模式(Factory Pattern)是创建型设计模式中应用最广泛的模式家族,它封装了对象的创建逻辑,让调用方无需关心具体的实现细节。工厂模式分为三种演进形态:简单工厂工厂方法抽象工厂。本文将通过一个"支付系统"的案例,逐步揭示它们的区别与适用场景。

学习建议:工厂模式的三种形态不是孤立存在的,而是一个随着需求复杂度增长而自然演进的过程。从一个小项目中"一个switch解决问题"的简单工厂,到产品种类增多后"为每个产品配一个工厂"的工厂方法,再到多产品族场景下"创建成套产品"的抽象工厂——这条演进脉络比记忆三种模式的类图更有价值。面试中常见的问题是让你比较这三种模式,并举例说明各自的使用场景。

一、简单工厂模式

简单工厂通过一个工厂类根据参数决定创建哪种产品实例:

// 产品接口publicinterfacePayment{voidpay(doubleamount);}// 具体产品publicclassAlipayimplementsPayment{@Overridepublicvoidpay(doubleamount){System.out.println("支付宝支付: ¥"+amount);}}publicclassWechatPayimplementsPayment{@Overridepublicvoidpay(doubleamount){System.out.println("微信支付: ¥"+amount);}}publicclassBankPayimplementsPayment{@Overridepublicvoidpay(doubleamount){System.out.println("银行卡支付: ¥"+amount);}}// 简单工厂publicclassPaymentFactory{publicstaticPaymentcreatePayment(Stringtype){switch(type){case"alipay":returnnewAlipay();case"wechat":returnnewWechatPay();case"bank":returnnewBankPay();default:thrownewIllegalArgumentException("不支持的支付方式: "+type);}}}// 客户端调用publicclassClient{publicstaticvoidmain(String[]args){Paymentpayment=PaymentFactory.createPayment("alipay");payment.pay(199.99);}}

优点:将创建与使用分离,调用方只关心接口。
缺点:新增支付方式需要修改工厂类的switch,违反开闭原则。适用于产品类型比较少且变化不频繁的场景。

简单工厂真的"简单"吗?虽然叫"简单工厂",但在实际项目中很容易变复杂。比如你的switch分支从3个增长到20个,每个分支的创建逻辑从new Xxx()变成了一堆初始化代码——这时候简单工厂就变成了一个"上帝类",违背单一职责原则。另外,简单工厂通常用static方法,无法被子类重写,缺乏扩展点。如果预见到产品种类会频繁增加,应该从一开始就使用工厂方法模式。

二、工厂方法模式

定义一个创建对象的接口,让子类决定实例化哪个类:

// 抽象工厂publicabstractclassPaymentFactory{publicabstractPaymentcreatePayment();// 通用业务逻辑可以放在工厂里publicvoidprocessPayment(doubleamount){Paymentpayment=createPayment();payment.pay(amount);System.out.println("支付记录已保存");}}// 具体工厂publicclassAlipayFactoryextendsPaymentFactory{@OverridepublicPaymentcreatePayment(){returnnewAlipay();}}publicclassWechatPayFactoryextendsPaymentFactory{@OverridepublicPaymentcreatePayment(){returnnewWechatPay();}}// 客户端调用publicclassClient{publicstaticvoidmain(String[]args){// 根据配置选择工厂PaymentFactoryfactory=newAlipayFactory();factory.processPayment(299.50);}}

优势:新增支付方式只需添加新的产品和工厂子类,无需修改已有代码,符合开闭原则。每个工厂只负责创建一种产品,职责单一。

不足:类的数量成倍增长。如果产品类型非常多,会出现大量的工厂子类。

如何取舍?当产品只有3-5种时,简单工厂的switch足够清晰;当产品达到10+种且仍在增长时,工厂方法的优势开始显现。但有一个折中方案——结合反射或SPI机制:将产品类名配置化,在工厂中用Class.forName(className).newInstance()动态创建,这样既保持了单一工厂的简洁,又不需要改代码。Spring的BeanFactory本质上就是这样做的:通过配置(XML或注解)注册Bean定义,工厂按需创建实例。

三、抽象工厂模式

抽象工厂创建一组相关相互依赖的产品族:

// 产品族A:PC端UI组件publicinterfaceButton{voidrender();}publicinterfaceTextField{voidrender();}// Windows实现publicclassWinButtonimplementsButton{@Overridepublicvoidrender(){System.out.println("渲染Windows风格按钮");}}publicclassWinTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("渲染Windows风格文本框");}}// Mac实现publicclassMacButtonimplementsButton{@Overridepublicvoidrender(){System.out.println("渲染Mac风格按钮");}}publicclassMacTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("渲染Mac风格文本框");}}// 抽象工厂:定义产品族接口publicinterfaceUIFactory{ButtoncreateButton();TextFieldcreateTextField();}// 具体工厂:Windows产品族publicclassWinUIFactoryimplementsUIFactory{@OverridepublicButtoncreateButton(){returnnewWinButton();}@OverridepublicTextFieldcreateTextField(){returnnewWinTextField();}}// 具体工厂:Mac产品族publicclassMacUIFactoryimplementsUIFactory{@OverridepublicButtoncreateButton(){returnnewMacButton();}@OverridepublicTextFieldcreateTextField(){returnnewMacTextField();}}// 客户端publicclassApplication{privateButtonbutton;privateTextFieldtextField;publicApplication(UIFactoryfactory){button=factory.createButton();textField=factory.createTextField();}publicvoidrenderUI(){button.render();textField.render();}publicstaticvoidmain(String[]args){Stringos=System.getProperty("os.name");UIFactoryfactory;if(os.contains("Windows")){factory=newWinUIFactory();}else{factory=newMacUIFactory();}Applicationapp=newApplication(factory);app.renderUI();}}

抽象工厂的核心在于产品族的概念。当系统中有一组产品需要一起使用时(如Windows UI套件、Mac UI套件),用抽象工厂确保使用同一产品族内的组件,避免混搭。

抽象工厂 vs 工厂方法的决策:最简单的判断标准是看"产品是否成组出现"。如果支付和退款总是成对使用(支付宝支付+支付宝退款、微信支付+微信退款),就可以用抽象工厂;如果只有一种产品类型,工厂方法就够用。强行在不合适的场景使用抽象工厂,会导致过度设计——代码量翻倍却没有带来实际价值。

四、三种工厂模式对比

维度简单工厂工厂方法抽象工厂
产品种类1种(多个变体)1种(多个变体)多种(产品族)
新增产品修改工厂类添加子类添加新工厂
符合开闭原则
复杂度
典型场景JDBC DriverManagerSpring BeanFactoryMyBatis SqlSessionFactory

五、Spring中的工厂模式应用

Spring的IoC容器本质上是一个巨大的工厂:

// 面试常问:BeanFactory和FactoryBean的区别// BeanFactory是IoC容器的顶层接口,是工厂方法模式的体现// FactoryBean是Spring提供的一个特殊Bean// FactoryBean示例@ComponentpublicclassHttpProxyFactoryBeanimplementsFactoryBean<HttpProxy>{@OverridepublicHttpProxygetObject(){returnnewHttpProxy("http://api.example.com");}@OverridepublicClass<?>getObjectType(){returnHttpProxy.class;}@OverridepublicbooleanisSingleton(){returntrue;}}

总结

工厂模式的核心思想是解耦对象的创建和使用。简单工厂是一个集中式工厂,适合产品类型固定的小项目;工厂方法将创建职责下放到子类,遵循开闭原则,适合需要灵活扩展的场景;抽象工厂处理产品族,适用于多套相关产品共存的系统。理解这三种模式的演进关系和应用场景,是设计好可扩展Java系统的关键。

终极理解:工厂模式解决的并不只是"怎么new对象"的问题——它解决的是"谁来负责创建对象"的职责分配问题。在面向对象设计中,"创建"本身就是一个值得封装的职责。把这层理解透了,你就能看懂Spring IoC为什么是工厂模式的集大成者:它不仅封装了创建,还管理了对象的整个生命周期(依赖注入、作用域、后置处理等)。

✅ 亮点总结

  • 简单工厂 → 工厂方法 → 抽象工厂的渐进式演进,展示了产品种类增加时设计的自然变化
  • 工厂方法遵循开闭原则——新增产品只需添加子工厂,无需修改已有代码
  • 抽象工厂确保产品族的一致性——Windows/Mac UI套件不能被混搭使用
  • BeanFactoryvsFactoryBean的辨析——面试高频题,前者是IoC容器,后者是特殊工厂Bean
  • 三种模式的维度对比表(产品种类、扩展方式、开闭原则、复杂度、典型场景)一目了然

适用场景

  • 多支付渠道接入——工厂方法为微信、支付宝、银联各自创建支付通道
  • 多数据库支持——抽象工厂创建MySQL/Oracle/PostgreSQL各自的Connection和Command对象
  • Spring Boot自动配置——@Configuration+@Bean注解本质就是工厂方法的声明式写法

扩展方向

  • Spring IoC容器源码深入:从BeanFactoryApplicationContext的层次结构理解工厂模式的框架级应用
  • 策略模式与工厂模式结合:工厂创建具体策略对象,策略执行不同行为,强强联合(推荐阅读下一篇:Java设计模式之代理模式)
  • SPI(Service Provider Interface)机制:Java SPI与Spring SPIspring.factories的工厂扩展点

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

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

立即咨询