当前位置: 首页 > news >正文

Java 23 种设计模式:从踩坑到精通 | 番外:工厂方法 vs 抽象工厂 —— 从单产品到产品族,架构如何演进?

Java 23 种设计模式:从踩坑到精通 | 番外:工厂方法 vs 抽象工厂 —— 从单产品到产品族,架构如何演进?

摘要:工厂方法和抽象工厂都是创建型模式,都用于解耦对象的创建与使用。但它们的核心区别在于粒度——工厂方法解决单一产品类型的横向扩展,抽象工厂解决产品族的纵向创建。本文从支付渠道对接的真实场景出发,沿着“简单工厂 → 工厂方法 → 抽象工厂”的演进路线,结合代码对比、UML 分析和 Spring、MyBatis 源码,帮你彻底搞懂这对“创建型兄弟”的选型边界。

🗺️本文阅读地图(3 分钟速览)

  • 为什么支付+收款必须成套创建?
  • 简单工厂 → 工厂方法 → 抽象工厂:一张图看懂演进
  • UML 对比:单一产品 vs 产品族,继承 vs 组合
  • 手写代码对比:从一坨 if-else 到可插拔的工厂架构
  • SpringBeanFactoryvsFactoryBean,MyBatisSqlSessionFactory如何体现
  • 面试必问:“工厂方法和抽象工厂怎么选?抽象工厂完全符合开闭原则吗?”

📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 |当前:番外 · 工厂方法 vs 抽象工厂
🔗 返回系列总目录


文章目录

  • Java 23 种设计模式:从踩坑到精通 | 番外:工厂方法 vs 抽象工厂 —— 从单产品到产品族,架构如何演进?
    • 1. 从“支付渠道对接”的架构演进说起
    • 2. UML 对比:单一产品 vs 产品族
      • 2.1 工厂方法 UML(一个工厂一个产品)
      • 2.2 抽象工厂 UML(一个工厂一族产品)
    • 3. 三大核心区别
    • 4. 代码演进:从简单工厂到抽象工厂
      • 4.1 简单工厂(最简陋)
      • 4.2 工厂方法(单产品扩展)
      • 4.3 抽象工厂(产品族成套创建)
    • 5. 框架中的体现
      • 5.1 Spring:`BeanFactory` vs `FactoryBean`
      • 5.2 MyBatis:`SqlSessionFactory`
    • 6. 面试必问 + 追问连环炮
    • 🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

1. 从“支付渠道对接”的架构演进说起

假设你正在开发一个电商平台的支付模块,最初只需要支持支付宝支付。你写了一个简单工厂,根据参数创建支付对象:

// 简单工厂:一个工厂创建多种产品publicclassPayFactory{publicstaticIPaycreate(Stringchannel){if("alipay".equals(channel))returnnewAliPay();if("wechat".equals(channel))returnnewWxPay();thrownewIllegalArgumentException("不支持的支付渠道");}}

后来业务发展,你发现支付和收款必须成套创建——用户用支付宝付了款,就必须用支付宝的收款接口去对账,否则出现“串渠道”的生产事故。这时候简单工厂的弊端暴露无遗:它无法保证“支付对象”和“收款对象”来自同一个渠道。

于是架构演进开始:先用工厂方法让每个渠道有独立的工厂,再用抽象工厂为每个渠道提供一整套产品族(支付 + 收款)。


2. UML 对比:单一产品 vs 产品族

2.1 工厂方法 UML(一个工厂一个产品)

2.2 抽象工厂 UML(一个工厂一族产品)

UML 的关键差异

  • 工厂方法的抽象工厂接口只有一个createProduct()方法,抽象工厂有多个创建方法(createPay()+createCollect());
  • 工厂方法的一个具体工厂对应一个具体产品,抽象工厂的一个具体工厂对应一个产品族(一组关联产品)。

3. 三大核心区别

对比维度工厂方法抽象工厂
意图定义创建对象的接口,让子类决定实例化哪个类创建一系列相关或相互依赖的对象(产品族)
工厂职责一个工厂只创建一种产品一个工厂创建一族产品
扩展方向新增产品只需新加工厂类,完全符合开闭原则新增产品族符合开闭原则;但新增产品类型(如新增退款功能)需要修改抽象工厂接口和所有具体工厂,违反开闭原则
典型应用SpringFactoryBean、简单支付扩展MyBatisSqlSessionFactory、支付+收款成套创建

💡简单记忆:工厂方法是“一个产品一条生产线”,抽象工厂是“一族产品一个集团”。工厂方法加产品 = 加一条线;抽象工厂加产品类型 = 整个集团都要改。


4. 代码演进:从简单工厂到抽象工厂

4.1 简单工厂(最简陋)

// 简单工厂:一个工厂,根据参数返回不同产品publicclassSimplePayFactory{publicstaticIPaycreatePay(Stringchannel){switch(channel){case"alipay":returnnewAliPay();case"wechat":returnnewWxPay();default:thrownewIllegalArgumentException("不支持的渠道");}}}

⚠️ 问题:新增渠道需修改switch,违反开闭原则;无法保证支付和收款配套。

4.2 工厂方法(单产品扩展)

// 工厂方法:每个渠道一个工厂,只创建支付对象publicinterfacePayFactory{IPaycreatePay();}publicclassAliPayFactoryimplementsPayFactory{@OverridepublicIPaycreatePay(){returnnewAliPay();}}publicclassWxPayFactoryimplementsPayFactory{@OverridepublicIPaycreatePay(){returnnewWxPay();}}

✅ 优点:新增渠道只需加新工厂类。
⚠️ 问题:收款对象需要另外创建,无法保证支付和收款来自同一渠道。

4.3 抽象工厂(产品族成套创建)

// 抽象工厂:一个工厂同时创建支付和收款publicabstractclassPaymentFactory{publicabstractIPaycreatePay();publicabstractICollectcreateCollect();}publicclassAliPaymentFactoryextendsPaymentFactory{@OverridepublicIPaycreatePay(){returnnewAliPay();}@OverridepublicICollectcreateCollect(){returnnewAliCollect();}}publicclassWxPaymentFactoryextendsPaymentFactory{@OverridepublicIPaycreatePay(){returnnewWxPay();}@OverridepublicICollectcreateCollect(){returnnewWxCollect();}}

✅ 优点:支付和收款强制配套,杜绝“串渠道”;切换渠道只需替换工厂实例。
⚠️ 缺点:如果需要新增“退款”产品,必须修改PaymentFactory抽象类和所有具体工厂。

演进总结

简单工厂 工厂方法 抽象工厂 ──────→ ──────→ ──────→ 一个工厂,多种产品 每个产品一个工厂 一个工厂,一族产品 集中但违反OCP 扩展性强 保证产品族一致 支付场景起步 支付扩展 支付+收款配套

5. 框架中的体现

5.1 Spring:BeanFactoryvsFactoryBean

  • BeanFactory:IoC 容器的核心接口,负责管理和创建所有 Bean。它不关心具体产品,可以看作一个超级“抽象工厂”。
  • FactoryBean<T>:一个专门用于创建复杂对象的工厂 Bean,每次getObject()返回一个特定类型的产品。这是典型的工厂方法模式——每个FactoryBean只创建一种产品。
// FactoryBean:工厂方法模式@ComponentpublicclassMyServiceFactoryBeanimplementsFactoryBean<MyService>{@OverridepublicMyServicegetObject(){returnnewMyService();}// 只创建一种产品@OverridepublicClass<?>getObjectType(){returnMyService.class;}}

5.2 MyBatis:SqlSessionFactory

SqlSessionFactory是典型的抽象工厂模式——它创建SqlSession以及与当前数据库环境关联的ConfigurationTransaction等对象,构成一个完整的产品族。切换数据库环境只需替换SqlSessionFactory的实现。


6. 面试必问 + 追问连环炮

基础必问

  • 工厂方法和抽象工厂的区别?
    👉 工厂方法解决单一产品扩展,抽象工厂解决产品族创建。工厂方法的抽象工厂只有一个create()方法,抽象工厂有多个。
  • 抽象工厂完全符合开闭原则吗?
    👉 不完全。新增产品族(新增一个支付渠道)符合 OCP;但新增产品类型(如新增退款功能)需要修改抽象工厂接口和所有具体工厂,违反 OCP。这是面试中经常考察的点。

面试官追问

  • “什么时候该用抽象工厂而不是工厂方法?”
    👉 当系统需要创建的对象之间存在“成套”或“风格统一”的强关联时。如支付+收款必须来自同一渠道、跨平台 UI 的按钮+文本框必须风格一致。
  • BeanFactoryFactoryBean分别是什么模式?”
    👉BeanFactory是抽象工厂模式(管理所有 Bean 的容器),FactoryBean是工厂方法模式(生产特定复杂对象的工厂)。
  • “简单工厂、工厂方法、抽象工厂如何演进?”
    👉 产品种类少且固定 → 简单工厂;产品种类多、频繁新增 → 工厂方法;产品成族出现、需整体切换 → 抽象工厂。三者是一个“从集中到分散、从单产品到产品族”的演进过程。

🎉恭喜:如果你能立刻画出工厂方法和抽象工厂的 UML 对比图,并说出“新增产品类型时抽象工厂违反 OCP”,你已经掌握了创建型模式最核心的选型逻辑。

💡延伸阅读:本文是工厂方法模式与抽象工厂模式的深度对比。如果你想先了解每种模式的完整原理、UML、代码实现和面试题,可以先阅读正篇——工厂模式:简单工厂→工厂方法→抽象工厂全演进 和 抽象工厂模式:产品族创建,如何避免“一锅粥”?,再回来看这篇对比,效果更佳。


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

  • 开篇:系列介绍与目录
  • 当前:番外 · 工厂方法 vs 抽象工厂 —— 从单产品到产品族,架构如何演进?(你在这里)
  • 📖 延伸阅读:工厂模式正篇 | 抽象工厂模式正篇
  • 创建型模式汇总
  • 结构型模式汇总
  • 行为型模式汇总

🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。

📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。

http://www.jsqmd.com/news/1182419/

相关文章:

  • AMD Ryzen AI生态新成员:Meta-Llama-3.1-8B-Instruct_rai_1.7.1_npu_16K模型评测与前景展望
  • 免费解锁Wand专业版:终极完整指南,告别订阅费
  • 高级技巧:如何微调Qwen2.5-Coder-1.5B-Instruct_rai_1.7.1_npu_4K以适应特定编程语言
  • 如何掌握PHP聚合根(Aggregate Root)设计与实现:state-of-the-union项目的终极指南
  • 【厦门集美区地域拆解】厦门首饰回收哪家正规 公安备案资质可开具书面回收单据 - 讯息早知道
  • 猫抓浏览器扩展:网页媒体资源一键获取的终极解决方案
  • Prettier + ESLint + Cursor三端协同配置,深度解耦格式化冲突的7步标准化流程
  • Llama-3.2-1B_rai_1.7.1_npu_4K模型文件结构解析:从ONNX到量化参数
  • LuaJIT字节码反编译终极指南:如何高效恢复Lua源代码
  • DeepSeek是如何让token们学会偷懒的
  • 【公众号】baoyu 的 `remote-api` 模式
  • AMD量化模型兼容性指南:Qwen2.5-VL-7B-Instruct-w4a16-asym-torchao-v0.17.0版本锁定解析
  • AMD SmolLM-135M-Instruct_rai_1.7.1_npu_4K模型对比分析:与其他轻量级模型的性能差异
  • OpenMotor:免费开源的终极火箭发动机模拟器,轻松设计你的火箭引擎
  • 如何用tochd将游戏ISO转换为CHD格式:完整指南
  • LuaJIT字节码反编译终极指南:5分钟从二进制到可读源码的魔法转变
  • 基于springboot企事业单位采购网站
  • GitHub Desktop中文汉化:开发者如何通过本地化工具提升开发体验
  • 从入门到精通:Phi-3.5-mini-instruct_rai_1.7.1_npu_4K在Ryzen AI平台的全方位应用指南
  • kokoro_mlx高级技巧:如何优化语音合成质量与性能 [特殊字符]
  • Unity Terrain Tools进阶:打造风格化森林与草地的完整工作流
  • 欧米茄官方售后服务中心电话及服务网点地址实地考察报告_多信源验证(2026年7月更新) - 欧米茄服务中心
  • 提示词响应延迟骤增?DeepSeek最新v3.2模型适配策略,3分钟定位并修复提示词结构缺陷
  • Llama-2-7b-hf_rai_1.7.1_npu_4K与其他NPU模型对比:4K上下文带来的终极优势分析
  • 告别快捷键记忆混乱:VSCode IntelliJ IDEA快捷键插件的效率革命
  • 揭秘VForm 3:5种实战场景下如何用Vue 3低代码表单提升10倍开发效率
  • MOVA LINCO获数千万元天使融资,三款产品构建家庭AI基础设施
  • Perplexity提示工程实战手册(2024最新版):覆盖92%高频场景的23个高转化Prompt模板
  • Matter ZAP插件开发终极指南:如何定制你的智能设备代码生成器
  • 如何快速部署NVIDIA Kimi-K2.6-Eagle3:TensorRT-LLM实战教程