Java 23 种设计模式从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建跨平台 UI 如何一键换肤摘要当系统需要同时创建多个有内在关联的产品对象时如不同支付渠道的支付收款或跨平台 UI 的按钮文本框简单的工厂方法会导致工厂数量爆炸且难以保证产品族一致性。本文带你深入抽象工厂模式用支付产品族和跨平台 UI 换肤两个实战案例彻底搞懂“产品族”与“产品等级结构”并给出与工厂方法的终极选型指南。《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 上一篇工厂模式 当前抽象工厂模式 下一篇建造者模式 返回系列总目录1. 从一个“换肤”需求说起假设你正在开发一套跨平台的 UI 组件库需要同时支持 Windows 风格和 Mac 风格。每个风格的组件都是一整套的按钮、文本框、下拉框…… 如果直接用new创建ButtonbtnnewWinButton();TextFieldtfnewWinTextField();当需要切换到 Mac 风格时你必须把每一个new的地方都改成new MacButton()、new MacTextField()。这不仅繁琐还容易漏改导致界面风格“串味”——变成一锅粥。更麻烦的是如果将来要新增一个 Linux 风格所有创建代码都得再改一遍。抽象工厂模式正是为了解决这类“产品族”创建问题而生的它把一族相关的产品交给一个专门的工厂来统一生产切换工厂就等于切换整个产品族保证风格绝对一致。2. 模式定义与核心概念抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。它属于创建型设计模式。2.1 两个关键概念产品等级结构即产品的继承结构。例如Button是一个抽象接口WinButton和MacButton是它的具体实现。Button和TextField属于不同的产品等级结构。产品族由同一个工厂生产的、位于不同产品等级结构中的一组产品。例如WinFactory生产的WinButtonWinTextField构成一个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 客户端GUIFactoryfactorynewWinFactory();Buttonbtnfactory.createButton();TextFieldtffactory.createTextField();btn.paint();// Windows 风格按钮tf.render();// Windows 风格文本框// 一键换肤factorynewMacFactory();btnfactory.createButton();tffactory.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 客户端PayFactoryfactorynewAliFactory();factory.init();factory.createPay().pay();factory.createCollect().collect();factorynewWxFactory();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智能调度实战》。技术相通思路可鉴。
Java 23 种设计模式:从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建?跨平台 UI 如何一键换肤?
Java 23 种设计模式从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建跨平台 UI 如何一键换肤摘要当系统需要同时创建多个有内在关联的产品对象时如不同支付渠道的支付收款或跨平台 UI 的按钮文本框简单的工厂方法会导致工厂数量爆炸且难以保证产品族一致性。本文带你深入抽象工厂模式用支付产品族和跨平台 UI 换肤两个实战案例彻底搞懂“产品族”与“产品等级结构”并给出与工厂方法的终极选型指南。《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 上一篇工厂模式 当前抽象工厂模式 下一篇建造者模式 返回系列总目录1. 从一个“换肤”需求说起假设你正在开发一套跨平台的 UI 组件库需要同时支持 Windows 风格和 Mac 风格。每个风格的组件都是一整套的按钮、文本框、下拉框…… 如果直接用new创建ButtonbtnnewWinButton();TextFieldtfnewWinTextField();当需要切换到 Mac 风格时你必须把每一个new的地方都改成new MacButton()、new MacTextField()。这不仅繁琐还容易漏改导致界面风格“串味”——变成一锅粥。更麻烦的是如果将来要新增一个 Linux 风格所有创建代码都得再改一遍。抽象工厂模式正是为了解决这类“产品族”创建问题而生的它把一族相关的产品交给一个专门的工厂来统一生产切换工厂就等于切换整个产品族保证风格绝对一致。2. 模式定义与核心概念抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。它属于创建型设计模式。2.1 两个关键概念产品等级结构即产品的继承结构。例如Button是一个抽象接口WinButton和MacButton是它的具体实现。Button和TextField属于不同的产品等级结构。产品族由同一个工厂生产的、位于不同产品等级结构中的一组产品。例如WinFactory生产的WinButtonWinTextField构成一个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 客户端GUIFactoryfactorynewWinFactory();Buttonbtnfactory.createButton();TextFieldtffactory.createTextField();btn.paint();// Windows 风格按钮tf.render();// Windows 风格文本框// 一键换肤factorynewMacFactory();btnfactory.createButton();tffactory.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 客户端PayFactoryfactorynewAliFactory();factory.init();factory.createPay().pay();factory.createCollect().collect();factorynewWxFactory();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智能调度实战》。技术相通思路可鉴。