Java 23 种设计模式:从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建?跨平台 UI 如何一键换肤?
2026/6/1 8:55:39 网站建设 项目流程

Java 23 种设计模式:从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建?跨平台 UI 如何一键换肤?

摘要:当系统需要同时创建多个有内在关联的产品对象时(如不同支付渠道的支付+收款,或跨平台 UI 的按钮+文本框),简单的工厂方法会导致工厂数量爆炸且难以保证产品族一致性。本文带你深入抽象工厂模式,用支付产品族跨平台 UI 换肤两个实战案例,彻底搞懂“产品族”与“产品等级结构”,并给出与工厂方法的终极选型指南。

📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 | 上一篇:工厂模式 |当前:抽象工厂模式| 下一篇:建造者模式
🔗 返回系列总目录


1. 从一个“换肤”需求说起

假设你正在开发一套跨平台的 UI 组件库,需要同时支持 Windows 风格和 Mac 风格。每个风格的组件都是一整套的:按钮、文本框、下拉框…… 如果直接用new创建:

Buttonbtn=newWinButton();TextFieldtf=newWinTextField();

当需要切换到 Mac 风格时,你必须把每一个new的地方都改成new MacButton()new MacTextField()。这不仅繁琐,还容易漏改,导致界面风格“串味”——变成一锅粥。

更麻烦的是,如果将来要新增一个 Linux 风格,所有创建代码都得再改一遍。

抽象工厂模式正是为了解决这类“产品族”创建问题而生的:它把一族相关的产品交给一个专门的工厂来统一生产,切换工厂就等于切换整个产品族,保证风格绝对一致。


2. 模式定义与核心概念

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它属于创建型设计模式

2.1 两个关键概念

  • 产品等级结构:即产品的继承结构。例如Button是一个抽象接口,WinButtonMacButton是它的具体实现。ButtonTextField属于不同的产品等级结构。
  • 产品族:由同一个工厂生产的、位于不同产品等级结构中的一组产品。例如WinFactory生产的WinButton+WinTextField构成一个Windows 产品族

2.2 一分钟选型指南

你的场景推荐模式一句话理由
单一产品类型,但需要灵活扩展工厂方法每新增一个产品只需加一个工厂类,符合开闭原则
多个产品类型成套出现,需要整体切换抽象工厂一个工厂生产一族产品,保证风格/协议一致
产品类型数量不固定,未来可能新增产品类型谨慎使用抽象工厂新增产品类型(如新增Checkbox)需要改动所有工厂,代价高

3. UML 类图


4. 代码实现:跨平台 UI 组件库(经典案例)

4.1 抽象产品

publicinterfaceButton{voidpaint();}publicinterfaceTextField{voidrender();}

4.2 具体产品(Windows 风格)

publicclassWinButtonimplementsButton{@Overridepublicvoidpaint(){System.out.println("渲染 Windows 风格按钮");}}publicclassWinTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("渲染 Windows 风格文本框");}}

4.3 具体产品(Mac 风格)

publicclassMacButtonimplementsButton{@Overridepublicvoidpaint(){System.out.println("渲染 Mac 风格按钮");}}publicclassMacTextFieldimplementsTextField{@Overridepublicvoidrender(){System.out.println("渲染 Mac 风格文本框");}}

4.4 抽象工厂

publicinterfaceGUIFactory{ButtoncreateButton();TextFieldcreateTextField();}

4.5 具体工厂

publicclassWinFactoryimplementsGUIFactory{@OverridepublicButtoncreateButton(){returnnewWinButton();}@OverridepublicTextFieldcreateTextField(){returnnewWinTextField();}}publicclassMacFactoryimplementsGUIFactory{@OverridepublicButtoncreateButton(){returnnewMacButton();}@OverridepublicTextFieldcreateTextField(){returnnewMacTextField();}}

✅ 切换工厂只需改动一行代码,整个产品族同步切换,彻底杜绝“串味”风险。

4.6 客户端

GUIFactoryfactory=newWinFactory();Buttonbtn=factory.createButton();TextFieldtf=factory.createTextField();btn.paint();// Windows 风格按钮tf.render();// Windows 风格文本框// 一键换肤factory=newMacFactory();btn=factory.createButton();tf=factory.createTextField();

5. 代码实现:支付产品族(支付 + 收款)

5.1 抽象产品

publicinterfaceIPay{voidpay();}publicinterfaceICollect{voidcollect();}

5.2 具体产品(阿里系)

publicclassAliPayimplementsIPay{publicvoidpay(){System.out.println("【支付宝】支付成功");}}publicclassAliCollectimplementsICollect{publicvoidcollect(){System.out.println("【支付宝】收款到账");}}

5.3 具体产品(微信系)

publicclassWxPayimplementsIPay{publicvoidpay(){System.out.println("【微信】支付成功");}}publicclassWxCollectimplementsICollect{publicvoidcollect(){System.out.println("【微信】收款到账");}}

5.4 抽象工厂

publicabstractclassPayFactory{publicvoidinit(){System.out.println("初始化支付环境...");}publicabstractIPaycreatePay();publicabstractICollectcreateCollect();}

5.5 具体工厂

publicclassAliFactoryextendsPayFactory{publicIPaycreatePay(){returnnewAliPay();}publicICollectcreateCollect(){returnnewAliCollect();}}publicclassWxFactoryextendsPayFactory{publicIPaycreatePay(){returnnewWxPay();}publicICollectcreateCollect(){returnnewWxCollect();}}

✅ 同一个工厂保证了支付和收款使用同一渠道,客户端只与抽象工厂交互,扩展新渠道只需新增一个工厂类。

5.6 客户端

PayFactoryfactory=newAliFactory();factory.init();factory.createPay().pay();factory.createCollect().collect();factory=newWxFactory();factory.init();factory.createPay().pay();

6. 优缺点一览

优点缺点
保证产品族一致性:同一工厂的所有产品风格/协议天然兼容新增产品等级困难:若要新增一个产品类型(如Checkbox),抽象工厂及所有具体工厂都要修改
切换产品族极其简单:只需更换工厂实例类数量增加,系统复杂
客户端与具体产品解耦仅适用于存在产品族且产品等级相对稳定的场景

7. 抽象工厂 vs 工厂方法

对比维度工厂方法抽象工厂
解决问题单一产品的横向扩展产品族的纵向创建
工厂数量每个产品一个工厂每个产品族一个工厂
扩展方向新增产品只需新增工厂类(符合 OCP)新增产品族只需新增工厂类(符合 OCP),新增产品类型需修改抽象工厂(违反 OCP)
典型场景单一支付方式扩展支付渠道 + 收款渠道的成套创建

💡口诀:一个产品横向扩展用工厂方法,一族产品成套创建用抽象工厂。


8. 框架中的抽象工厂

  • MyBatis 的SqlSessionFactory:负责创建SqlSession及关联的Configuration,确保它们属于同一个数据库环境。
  • JDBC 的DataSource:提供getConnection(),连接、语句、结果集构成一套完整的产品族。
  • Spring 的AbstractBeanFactory:保证 Bean 的依赖、作用域、生命周期管理的一致性。

9. 常见误区与面试高频题

❌ 误区1:抽象工厂就是升级版的工厂方法
两者解决不同维度的问题,没有高低之分。

❌ 误区2:抽象工厂完全符合开闭原则
只在产品族维度上符合 OCP,在产品等级维度上违反 OCP。

💡 面试高频追问

  • 抽象工厂如何保证产品族一致性?→ 同一工厂实例创建的所有产品都属于同一产品族。
  • 什么时候该用抽象工厂而不是工厂方法?→ 当系统需要创建的对象之间存在“成套”或“风格统一”的强关联时。
  • 抽象工厂的缺点?→ 新增产品类型困难,需要修改抽象工厂及所有具体工厂。

10. 六大设计原则在抽象工厂中的体现

设计原则体现
单一职责(SRP)每个具体工厂只负责一个产品族
开闭原则(OCP)新增产品族无需修改现有代码(但新增产品类型需修改)
里氏替换(LSP)所有产品族都可替换抽象工厂和抽象产品
依赖倒置(DIP)客户端依赖抽象,不依赖具体工厂
接口隔离(ISP)抽象工厂按产品族拆分接口,避免臃肿
迪米特法则(LoD)客户端只与抽象工厂交互,不接触具体产品

附录:| Abstract Factory UML 源码

@startuml skinparam backgroundColor #FEFEFE interface Button { + paint() } interface TextField { + render() } class WinButton implements Button class MacButton implements Button class WinTextField implements TextField class MacTextField implements TextField interface GUIFactory { + createButton() : Button + createTextField() : TextField } class WinFactory implements GUIFactory class MacFactory implements GUIFactory WinFactory ..> WinButton : creates WinFactory ..> WinTextField : creates MacFactory ..> MacButton : creates MacFactory ..> MacTextField : creates @enduml

🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

  • 开篇:系列介绍与目录
  • 上一篇:工厂模式
  • 当前:抽象工厂模式(你在这里)
  • 下一篇:建造者模式 🚧 即将发布
  • 创建型模式汇总:单例、工厂、建造者、原型
  • 结构型模式汇总:适配器、装饰器、代理……
  • 行为型模式汇总:观察者、策略、模板方法……

🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
🚀下一篇:建造者模式 —— 构造器参数太多?试试链式调用!🚧 即将发布,敬请关注!
📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。

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

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

立即咨询