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

设计模式系列文章(基础篇第 3 篇):工厂方法模式——解耦对象创建与使用

大家好,欢迎来到设计模式系列文章(基础篇)的第三篇内容。在上一篇中,我们学习了创建型模式的第一种——单例模式,它的核心是保证“全局唯一实例”;而今天我们要学习的工厂方法模式,同样属于创建型模式,但其核心目标更偏向于“解耦”——将对象的创建过程与使用过程分离,让对象的创建交由专门的“工厂”负责,我们无需关注对象如何创建,只需专注于对象的使用,从而提升代码的灵活性和可扩展性。
在正式讲解之前,我们先想一个日常开发中的常见场景:假设我们要开发一个支付系统,支持支付宝、微信支付、银联支付三种支付方式。如果不使用设计模式,我们会在代码中直接通过new关键字创建不同的支付对象,比如需要支付宝支付就new Alipay(),需要微信支付就new WechatPay()。这种方式看似简单,但存在一个严重的问题:如果后续需要新增支付方式(如京东支付),就必须修改所有创建支付对象的代码,不仅繁琐,还会导致代码耦合度极高,不符合“开闭原则”。
而工厂方法模式,就完美解决了这个问题。它通过引入“工厂”角色,将对象的创建逻辑封装在工厂中,我们只需调用工厂的方法,就能获取所需的对象,无需关心对象的创建细节。后续新增对象类型时,只需新增对应的工厂,无需修改原有代码,真正实现“对扩展开放、对修改关闭”。今天,我们就从工厂方法模式的核心思想出发,讲解它的定义、结构、实现方式,以及与简单工厂模式的区别,帮大家彻底掌握这种常用的创建型模式。

一、工厂方法模式的核心定义与设计初衷

1. 核心定义
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
通俗地说,工厂方法模式就像一个“对象生产车间”:我们定义一个统一的“工厂接口”,规定所有工厂都必须实现“生产对象”的方法;然后为每一种对象类型,创建一个对应的“具体工厂”,由具体工厂负责生产对应的对象。我们使用时,只需找到对应的具体工厂,调用生产方法,就能得到所需对象,无需关心对象的创建细节。

2. 设计初衷(解决的核心问题)
工厂方法模式的出现,主要是为了解决“简单工厂模式”的缺陷(后续会对比两者),核心解决以下3个问题:

  • 解耦对象创建与使用:将对象创建逻辑从业务代码中分离,业务代码只需使用对象,无需关注创建过程,降低代码耦合度;
  • 满足开闭原则:新增对象类型时,无需修改原有工厂代码,只需新增具体对象类和对应的具体工厂,扩展性强;
  • 统一对象创建标准:通过工厂接口规范所有工厂的行为,确保所有对象的创建都遵循统一的标准,提升代码的规范性和可维护性。

3. 设计原则适配
工厂方法模式严格遵循创建型模式的核心设计原则,重点体现以下3点:

  • 开闭原则:新增产品(对象)时,只需新增具体产品类和具体工厂类,无需修改原有工厂接口和业务代码,对扩展开放、对修改关闭;
  • 单一职责原则:每个具体工厂只负责生产一种具体产品,每个产品类只负责自身的业务逻辑,职责单一,便于维护;
  • 依赖倒转原则:业务代码依赖于工厂接口和产品接口,而非具体的工厂类和产品类,降低了依赖的耦合度,提升了代码的灵活性。

二、工厂方法模式的核心结构(4个角色)

工厂方法模式有4个核心角色,缺一不可,它们相互配合,实现对象的创建与使用分离。我们结合支付系统的场景,逐一讲解每个角色的作用:
1. 抽象产品(Abstract Product)
定义所有具体产品(对象)的共同接口或抽象类,规范产品的核心行为。比如支付系统中,所有支付方式都有“支付”“退款”两个核心行为,因此抽象产品就是“支付接口”,定义这两个方法。

2. 具体产品(Concrete Product)
实现抽象产品接口,是工厂方法模式最终要创建的对象。比如支付系统中的“支付宝支付”“微信支付”“银联支付”,都是具体产品,它们分别实现抽象产品的“支付”“退款”方法,实现各自的业务逻辑。

3. 抽象工厂(Abstract Factory)
定义一个用于创建产品的接口,包含一个“创建产品”的抽象方法,所有具体工厂都必须实现这个接口。比如支付系统中的“支付工厂接口”,定义一个“创建支付对象”的方法。

4. 具体工厂(Concrete Factory)
实现抽象工厂接口,负责创建对应的具体产品。比如“支付宝工厂”负责创建支付宝支付对象,“微信支付工厂”负责创建微信支付对象,每个具体工厂只对应一种具体产品。
核心关系总结:抽象工厂定义创建产品的标准,具体工厂实现标准并创建具体产品,具体产品实现抽象产品的行为,业务代码通过调用具体工厂的方法,获取具体产品并使用。

三、工厂方法模式的实战实现(以支付系统为例)

我们依然以Java代码为例,结合支付系统的场景,一步步实现工厂方法模式,让大家直观理解每个角色的作用和代码落地方式。
1. 第一步:定义抽象产品(支付接口)
定义所有支付方式的共同接口,规范“支付”和“退款”两个核心行为:

// 抽象产品:支付接口 public interface Payment{// 支付方法 void pay(double amount);// 退款方法 void refund(double amount);}

2. 第二步:实现具体产品(具体支付方式)
分别实现支付宝支付、微信支付、银联支付,各自实现支付和退款的具体逻辑:

// 具体产品1:支付宝支付 public class Alipay implements Payment{@Override public void pay(double amount){System.out.println("使用支付宝支付:"+ amount +"元");}@Override public void refund(double amount){System.out.println("支付宝退款:"+ amount +"元");}}// 具体产品2:微信支付 public class WechatPay implements Payment{@Override public void pay(double amount){System.out.println("使用微信支付:"+ amount +"元");}@Override public void refund(double amount){System.out.println("微信退款:"+ amount +"元");}}// 具体产品3:银联支付 public class UnionPay implements Payment{@Override public void pay(double amount){System.out.println("使用银联支付:"+ amount +"元");}@Override public void refund(double amount){System.out.println("银联退款:"+ amount +"元");}}

3. 第三步:定义抽象工厂(支付工厂接口)
定义创建支付对象的接口,包含一个抽象的创建方法:

// 抽象工厂:支付工厂接口 public interface PaymentFactory{// 抽象创建方法:返回支付对象 Payment createPayment();}

4. 第四步:实现具体工厂(对应具体支付方式)
为每种支付方式创建对应的具体工厂,实现抽象工厂的创建方法,返回对应的具体支付对象:

// 具体工厂1:支付宝工厂 public class AlipayFactory implements PaymentFactory{@Override public PaymentcreatePayment(){// 负责创建支付宝支付对象returnnew Alipay();}}// 具体工厂2:微信支付工厂 public class WechatPayFactory implements PaymentFactory{@Override public PaymentcreatePayment(){// 负责创建微信支付对象returnnew WechatPay();}}// 具体工厂3:银联支付工厂 public class UnionPayFactory implements PaymentFactory{@Override public PaymentcreatePayment(){// 负责创建银联支付对象returnnew UnionPay();}}

5. 第五步:业务代码调用(使用工厂创建对象)
业务代码无需直接new支付对象,只需创建对应的具体工厂,调用createPayment()方法,即可获取支付对象并使用,实现创建与使用分离:

// 业务代码测试 public class PaymentTest{public static void main(String[]args){//1. 使用支付宝支付 PaymentFactory alipayFactory=new AlipayFactory();Payment alipay=alipayFactory.createPayment();alipay.pay(100.0);alipay.refund(50.0);//2. 使用微信支付 PaymentFactory wechatPayFactory=new WechatPayFactory();Payment wechatPay=wechatPayFactory.createPayment();wechatPay.pay(200.0);wechatPay.refund(100.0);//3. 使用银联支付 PaymentFactory unionPayFactory=new UnionPayFactory();Payment unionPay=unionPayFactory.createPayment();unionPay.pay(300.0);unionPay.refund(150.0);}}

运行结果

使用支付宝支付:100.0元 支付宝退款:50.0元 使用微信支付:200.0元 微信退款:100.0元 使用银联支付:300.0元 银联退款:150.0元

核心优势体现
假设现在需要新增“京东支付”,我们只需做两步,无需修改任何原有代码:

  1. 新增具体产品:JdPay类,实现Payment接口;
  2. 新增具体工厂:JdPayFactory类,实现PaymentFactory接口,返回JdPay对象。
    这种方式完全符合开闭原则,扩展性极强,且业务代码无需任何修改,只需新增对应的工厂调用即可。

四、工厂方法模式 vs 简单工厂模式(重点区分)

很多人会混淆工厂方法模式和简单工厂模式,两者都属于创建型模式,核心都是解耦对象创建与使用,但存在本质区别。我们通过表格清晰对比,帮大家快速区分:

对比维度工厂方法模式简单工厂模式
核心结构抽象工厂+具体工厂+抽象产品+具体产品(4个角色)单一工厂+抽象产品+具体产品(3个角色)
对象创建逻辑每个具体工厂负责创建一种具体产品,职责单一一个工厂负责创建所有具体产品,逻辑集中
扩展性强,新增产品只需新增具体产品和具体工厂,无需修改原有代码(符合开闭原则)弱,新增产品需修改工厂的创建逻辑(不符合开闭原则)
复杂度稍高,需要定义多个工厂类简单,只需一个工厂类,代码简洁
适用场景产品种类多、易扩展,对扩展性要求高的场景产品种类少、变化少,对扩展性要求低的场景

补充说明:简单工厂模式是工厂方法模式的“简化版”,虽然简单,但扩展性差;工厂方法模式是简单工厂模式的“升级版”,通过拆分工厂职责,提升了扩展性,是日常开发中更推荐的方式。

五、工厂方法模式的常见应用场景

工厂方法模式的应用非常广泛,尤其是在产品种类多、易扩展的场景中,以下是3个最常见的实际应用场景,帮大家更好地落地:
1. 框架中的应用
很多主流框架都大量使用了工厂方法模式,比如Spring框架中的BeanFactory:

  • 抽象工厂:BeanFactory(定义创建Bean的接口);
  • 具体工厂:XmlBeanFactory、AnnotationConfigBeanFactory(不同的Bean创建工厂);
  • 抽象产品:Bean(所有Spring管理的对象);
  • 具体产品:我们定义的Service、Dao等类。
    我们通过Spring获取Bean时,无需关心Bean的创建过程,只需通过BeanFactory(或ApplicationContext)的方法获取,这就是工厂方法模式的典型应用。

2. 业务系统中的产品扩展场景
除了支付系统,以下场景也非常适合使用工厂方法模式:

  • 日志系统:支持文件日志、控制台日志、数据库日志,每种日志对应一个具体工厂;
  • 消息推送系统:支持短信推送、邮件推送、微信推送,每种推送方式对应一个具体工厂;
  • 文档解析系统:支持PDF解析、Word解析、Excel解析,每种解析方式对应一个具体工厂。

3. 工具类的统一创建场景
当一个系统中有多种功能相似但实现不同的工具类时,使用工厂方法模式可以统一创建入口,方便管理和扩展。比如文件操作工具,支持本地文件操作、FTP文件操作、云存储文件操作,每种操作对应一个具体工厂,业务代码可以灵活切换不同的文件操作方式。

六、工厂方法模式的常见坑与避坑指南

坑1:过度设计,滥用工厂方法模式
很多开发者为了追求“设计模式”,即使产品种类很少、几乎不会扩展,也强行使用工厂方法模式,导致代码冗余(需要定义多个工厂类)。比如一个系统只支持一种支付方式,却依然定义抽象工厂、具体工厂,完全没有必要。
避坑指南:如果产品种类少、变化少,优先使用简单工厂模式;只有当产品种类多、易扩展,且对扩展性要求高时,再使用工厂方法模式。

坑2:具体工厂职责不单一
部分开发者会在具体工厂中添加额外的业务逻辑(如支付工厂中添加支付验证逻辑),导致工厂职责不单一,违反“单一职责原则”,后续维护困难。
避坑指南:工厂的唯一职责就是“创建对象”,业务逻辑应放在具体产品类中,工厂只负责对象的实例化,不承担其他业务功能。

坑3:忽略抽象产品的设计
如果抽象产品定义的方法不够全面,后续新增具体产品时,可能需要修改抽象产品接口,违反开闭原则。比如支付接口只定义了pay()方法,后续新增的支付方式需要refund()方法,就必须修改抽象产品接口。
避坑指南:设计抽象产品时,要充分考虑所有具体产品的共同行为,提前定义好核心方法,避免后续修改抽象产品。

七、系列文章预告

本篇文章,我们详细讲解了工厂方法模式的核心定义、结构、实战实现,以及与简单工厂模式的区别,同时分享了常见坑与应用场景。相信大家已经能熟练运用工厂方法模式,解决“对象创建与使用分离”的需求,提升代码的扩展性和可维护性。
作为创建型模式的第二种常用模式,工厂方法模式解决了简单工厂模式的扩展性问题,但它依然存在一个局限:一个具体工厂只能创建一种具体产品。如果我们需要创建一组相关联的产品(比如电脑的CPU、显卡、内存,它们是一组关联产品),工厂方法模式就无法满足需求。
下一篇,我们将学习创建型模式的第三种——抽象工厂模式,它将解决“一组关联产品的创建”问题,进一步提升代码的设计能力。

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

相关文章:

  • 从零到一复现FlowNet-C:用PyTorch手把手搭建你的第一个光流估计网络(附完整代码)
  • 2026年优质网站建设公司精选:国内外服务商选型全指南
  • 别再傻傻做27次实验了!用SPSSAU三分钟搞定正交试验设计(附极差分析保姆级教程)
  • 如何快速获取最新FFmpeg:Windows用户的完整构建指南
  • Unity热更新实战:AB包+ILRuntime代码热更闭环方案
  • FastLED实例教程:10个精选项目带你玩转LED灯光效果
  • MATLAB搞DMS摄像头:为什么你拍到脸了,算法还是说“司机不在”?
  • TriADA架构:3D张量计算的高效加速方案
  • 如何ChatGPT和Gemini的回答导出文件
  • 本地视频转文字完全免费教程:video2text实现离线语音转写+AI智能总结
  • Blender MMD插件终极指南:3步解锁专业级MMD动画制作
  • 解决Stremio插件问题:stremio-addons-list常见错误与修复方案
  • HashCalculator:一键解决文件验证难题的终极哈希批量计算器
  • GPU资源管理优化:动态分配与多平台实践
  • AI懂不懂幽默
  • 告别混乱文件管理:用Minio的‘伪文件夹’实现清晰的数据分层与查询
  • WaveTools:提升《鸣潮》游戏体验的3大核心功能深度解析
  • VS Code + DeepSeek插件配置全链路故障排查(含token截断、context溢出、多文件联想失效三大暗坑)
  • 客户终身价值CLV:动态分群建模与实时计算实战指南
  • Kaggle新手必看:除了submission.csv,Windows上提交结果前你该检查的5个细节
  • CANoe测试中UDS 27服务安全算法调用避坑指南:从DLL编译错误到CAPL完美集成
  • 浙江保安公司推荐:2026浙江临时/靠谱专业安保公司汇总 - 栗子测评
  • 精通开源Switch模拟器:yuzu核心技术深度解析与实战配置指南
  • alexa-app框架错误处理与调试技巧:开发者必知的10个要点
  • 终极指南:3步掌握Wayback Machine批量下载神器
  • Smardaten多维可视化大屏|全网独家实战,无代码极速搭建篇 引入多源数据融合+交互联动增强,助力企业级监控中心快速落地、效能翻倍
  • 别再只盯着PF值了!聊聊LED电源设计中THD与PF的真实关系与取舍
  • Linux 自定义协议与序列化反序列化:从原理到落地
  • Linux多线程编程(二):互斥锁与条件变量,手写生产者消费者模型
  • 浙江口碑最好的安保公司推荐:2026浙江靠谱工厂外包保安公司甄选攻略 - 栗子测评