设计模式-三种工厂模式精讲(简单工厂、工厂方法、抽象方法)
如下是本文目录:
1. 为什么需要工厂模式
工厂模式是创建型设计模式,核心目标:封装对象的创建逻辑,统一对象生产入口,将对象创建与对象使用彻底解耦。
使用者无需关心对象的创建细节、依赖关系、初始化规则,只需通过统一工厂入口获取所需对象,大幅降低代码耦合度。
换句话讲:工厂模式就是把所有对象new创建、参数初始化、依赖装配、条件创建的重复代码抽离到统一工厂类,业务代码只负责使用对象,不负责创建对象,彻底实现「对象创建与业务使用分离」。
1.1 使用工厂模式要解决的核心痛点
a. 对象创建逻辑分散冗余:业务多处重复new同类对象,初始化参数、创建逻辑重复编写,修改时需要全量改动,维护成本极高;
b. 创建逻辑与业务逻辑强耦合:业务代码既要处理核心业务流程,又要维护对象创建规则,代码职责混乱,可读性、可维护性极差;
c. 复杂创建逻辑污染主流程:部分对象存在多参数初始化、条件分支创建、依赖嵌套等复杂逻辑,直接写在业务代码中会导致主流程臃肿、逻辑混乱;
d. 新增对象违反开闭原则:硬编码创建对象时,新增业务对象必须修改核心业务代码,破坏代码扩展性,迭代风险高;
e. 无法统一管控对象:对象零散创建,无法实现全局缓存、单例管控、统一初始化、配置适配,项目缺乏统一规范。
1.2 典型使用场景
a. 对象创建逻辑复杂、存在多条件分支创建的业务场景;
b. 系统需要批量创建相似、同系列、同品类对象的场景;
c. 对象创建规则动态变更、后续需要持续扩展产品类型的迭代场景;
d. 需要统一管控对象实例(缓存、单例、统一初始化、全局配置)的场景;
e. 客户端完全不需要感知对象创建细节,仅需使用对象的业务场景。
1.3 不适合工厂模式的场景
a. 对象创建逻辑极简:无参数、无判断、固定 new 对象,无需封装工厂,强行封装属于过度设计;
b. 产品类型永久固定:终身仅有单一对象、无任何新增扩展需求,工厂模式无实际意义;
c. 临时一次性对象:仅单次业务使用、无需复用、无需统一管理的临时对象;
d. 高频销毁重建的轻量化对象:无统一管控价值、生命周期极短的微小对象。
2. 工厂模式三大核心体系与实现方式
工厂模式是创建型模式的核心体系,整体分为简单工厂、工厂方法、抽象工厂三个层级,三者逐级优化、逐级复杂,开闭原则落地程度、代码扩展性、业务适配性逐级提升,分别适配不同复杂度的业务场景。
核心演进逻辑:从「单一工厂包办所有创建」到「一厂一品单一职责」,再到「一厂一族批量创建系列产品」,完美适配从简单业务到复杂组件化业务的全场景。
2.1 简单工厂模式(静态工厂·入门首选)
2.1.1 核心特点
简单工厂是工厂模式的最简实现,不属于GOF标准设计模式,但工程使用最广泛。
核心是通过一个统一的工厂类,根据传入的类型参数,通过条件判断创建不同的产品对象,收拢所有产品的创建逻辑,统一对象生产入口。
核心角色:
- 抽象产品:定义同品类所有产品的统一公共接口/抽象方法,规范产品行为;
- 具体产品:实现抽象产品接口,完成具体产品的专属业务逻辑;
- 工厂类:唯一创建入口,提供静态创建方法,根据类型参数匹配并生产对应产品。
2.1.2 实战案例(支付方式创建)
// 1. 抽象产品:支付统一接口(规范所有支付方式行为)
public interface Pay {
// 统一支付执行方法
void pay(BigDecimal amount);
}
// 2. 具体产品:微信支付
public class WechatPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付成功,支付金额:" + amount);
}
}
// 2. 具体产品:支付宝支付
public class AliPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付成功,支付金额:" + amount);
}
}
// 2. 具体产品:银行卡支付
public class BankPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("银行卡支付成功,支付金额:" + amount);
}
}
// 3. 简单工厂:统一支付生产工厂
public class PaySimpleFactory {
// 静态创建方法,客户端直接调用,无需实例化工厂
public static Pay createPay(String payType) {
if ("wechat".equals(payType)) {
return new WechatPay();
} else if ("ali".equals(payType)) {
return new AliPay();
} else if ("bank".equals(payType)) {
return new BankPay();
} else {
throw new IllegalArgumentException("不支持的支付方式");
}
}
}
// 测试调用
public class SimpleFactoryTest {
public static void main(String[] args) {
// 客户端无需手动new具体支付对象,完全由工厂创建
Pay wechatPay = PaySimpleFactory.createPay("wechat");
wechatPay.pay(new BigDecimal("199.9"));
Pay aliPay = PaySimpleFactory.createPay("ali");
aliPay.pay(new BigDecimal("299.9"));
}
}
2.1.3 优缺点与适用场景
优点:代码极简、上手成本低;统一收拢对象创建逻辑,彻底解放客户端new操作;减少代码冗余,统一对象创建规范。
缺点:违反开闭原则,新增产品必须修改工厂类的if/else分支逻辑;工厂类职责过重,产品数量过多时会导致工厂代码极度臃肿、维护困难。
适用场景:产品类型固定、迭代频率低、极少新增类型、产品数量少的简单对象创建场景,是小型业务、快速开发的首选。
2.2 工厂方法模式(标准核心·高扩展首选)
2.2.1 核心特点
工厂方法模式是针对简单工厂的核心缺陷优化而来,是GOF标准设计模式。
核心思想:工厂抽象、产品抽象、一一对应、单一职责。为每一个具体产品单独创建专属工厂,通过抽象工厂定义统一创建规范,具体工厂仅负责生产对应单一产品。
新增产品时只需新增对应产品类和工厂类,无需修改原有代码,完美符合开闭原则,彻底解决简单工厂扩展性差的问题。
核心角色:
- 抽象产品:统一所有产品的业务规范;
- 具体产品:实现抽象产品,完成专属业务逻辑;
- 抽象工厂:定义统一的产品创建方法,规范所有工厂行为;
- 具体工厂:每个工厂仅对应一款产品,只负责该产品的创建与初始化,严格单一职责。
2.2.2 实战案例(支付场景优化)
// 1. 抽象产品(与简单工厂一致,统一支付规范)
public interface Pay {
void pay(BigDecimal amount);
}
// 具体产品:微信支付
public class WechatPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付成功,支付金额:" + amount);
}
}
// 具体产品:支付宝支付
public class AliPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付成功,支付金额:" + amount);
}
}
// 2. 抽象工厂:统一工厂创建规范
public interface PayFactory {
// 统一产品创建方法,所有工厂必须实现
Pay createPay();
}
// 3. 具体工厂:微信支付工厂(仅生产微信支付产品)
public class WechatPayFactory implements PayFactory {
@Override
public Pay createPay() {
// 可封装微信支付专属的复杂初始化逻辑
return new WechatPay();
}
}
// 具体工厂:支付宝支付工厂(仅生产支付宝支付产品)
public class AliPayFactory implements PayFactory {
@Override
public Pay createPay() {
return new AliPay();
}
}
// 测试调用
public class FactoryMethodTest {
public static void main(String[] args) {
// 通过专属工厂获取对应产品,完全解耦
PayFactory wechatFactory = new WechatPayFactory();
Pay wechatPay = wechatFactory.createPay();
wechatPay.pay(new BigDecimal("99.9"));
PayFactory aliFactory = new AliPayFactory();
Pay aliPay = aliFactory.createPay();
aliPay.pay(new BigDecimal("169.9"));
}
}
2.2.3 优缺点与适用场景
优点:完全符合开闭原则、单一职责原则;工厂与产品一一对应,扩展灵活;新增产品零侵入原有代码,迭代风险低;每个工厂逻辑单一,便于维护、测试。
缺点:每新增一款产品,必须新增对应的工厂类,会产生类爆炸问题,小幅增加项目代码量和类文件数量。
适用场景:产品类型多、需要频繁横向扩展、对代码扩展性和稳定性要求高的企业级业务场景。
2.3 抽象工厂模式(高阶工程·系列产品首选)
2.3.1 核心特点
工厂方法模式仅能生产单一品类、单一等级的产品,无法适配多组件、多关联的系列化产品场景。抽象工厂模式作为工厂体系的高阶实现,核心用于解决关联系列产品的批量创建问题。
核心核心概念:产品等级、产品族
- 产品等级:同一功能、不同实现的单品,称为一个产品等级。(如微信支付、支付宝支付,都属于支付产品等级);
- 产品族:同一品牌/同一体系下的所有关联配套产品(如微信支付、微信退款、微信对账,属于微信产品族)。
通俗总结:工厂方法是「一厂造一品」,抽象工厂是「一厂造一整套系列产品」。
核心角色:抽象工厂(定义系列产品创建规范)、具体工厂(生产完整产品族)、抽象系列产品(多等级产品规范)、具体系列产品。
2.3.2 实战案例(支付+退款系列产品族)
// ========== 产品等级1:支付接口(系列产品1) ==========
public interface Pay {
void pay(BigDecimal amount);
}
public class WechatPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付:" + amount);
}
}
public class AliPay implements Pay {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付:" + amount);
}
}
// ========== 产品等级2:退款接口(系列产品2) ==========
public interface Refund {
void refund(BigDecimal amount);
}
public class WechatRefund implements Refund {
@Override
public void refund(BigDecimal amount) {
System.out.println("微信退款:" + amount);
}
}
public class AliRefund implements Refund {
@Override
public void refund(BigDecimal amount) {
System.out.println("支付宝退款:" + amount);
}
}
// ========== 抽象工厂:定义整套产品族创建规范 ==========
public interface PaymentFactory {
// 创建支付产品
Pay createPay();
// 创建退款产品
Refund createRefund();
}
// ========== 具体工厂:微信产品族工厂(生产微信全套产品) ==========
public class WechatPaymentFactory implements PaymentFactory {
@Override
public Pay createPay() {
return new WechatPay();
}
@Override
public Refund createRefund() {
return new WechatRefund();
}
}
// 具体工厂:支付宝产品族工厂(生产支付宝全套产品)
public class AliPaymentFactory implements PaymentFactory {
@Override
public Pay createPay() {
return new AliPay();
}
@Override
public Refund createRefund() {
return new AliRefund();
}
}
// 测试调用
public class AbstractFactoryTest {
public static void main(String[] args) {
// 一次性获取微信全套系列产品
PaymentFactory wechatFactory = new WechatPaymentFactory();
wechatFactory.createPay().pay(new BigDecimal("200"));
wechatFactory.createRefund().refund(new BigDecimal("50"));
// 一次性获取支付宝全套系列产品
PaymentFactory aliFactory = new AliPaymentFactory();
aliFactory.createPay().pay(new BigDecimal("300"));
}
}
2.3.3 优缺点与适用场景
优点:完美适配系列化、配套化产品批量创建;保证同一产品族的产品统一匹配、无错乱;产品族扩展灵活,代码高度解耦;统一管控系列产品创建逻辑。
缺点:新增产品等级时,需要修改抽象工厂及所有具体工厂,违反开闭原则;整体结构复杂、学习和维护成本高;过度设计风险高。
适用场景:存在多组关联配套产品的组件化业务,典型场景:操作系统UI组件(按钮/弹窗/输入框)、支付体系(支付/退款/对账)、文件操作(读写/加密/解析)。
3. 三大工厂模式全方位对比
| 模式 | 核心能力 | 开闭原则 | 类爆炸 | 复杂度 | 适用场景 |
| 简单工厂 | 单一工厂创建多类单品,统一入口 | 不满足(新增改工厂) | 无 | 极低 | 产品固定、极少扩展、简单创建场景 |
| 工厂方法 | 一厂一品,支持单品横向无限扩展 | 完全满足 | 有 | 中等 | 单品频繁扩展、高扩展性业务 |
| 抽象工厂 | 一厂一族,批量创建系列关联产品 | 产品族满足,产品等级不满足 | 较多 | 高 | 多系列配套产品、组件化业务 |
4. 工厂模式核心痛点与工程解决方案
4.1 工厂类/产品类过多(类爆炸)
问题描述:工厂方法、抽象工厂模式下,新增产品必须新增对应工厂类,长期迭代会导致项目类文件泛滥,结构臃肿。
解决方案:
1. 简单固定产品场景:优先使用简单工厂,无需拆分多个工厂类,收拢代码;
2. 规范化分包管理:统一建立factory(工厂)、product(产品)、impl(实现类)分包,规整项目结构;
3. Spring 工程优化:将工厂、产品交由容器托管,利用单例特性减少冗余实例,简化配置。
4.2 简单工厂违反开闭原则
问题描述:简单工厂依赖硬编码 if/else 分支,新增产品必须修改工厂核心代码,存在迭代风险。
解决方案:
1. 需频繁扩展的场景,直接升级为工厂方法模式;
2. 折中优化:通过配置文件、枚举映射产品类型,消除硬编码分支;
3. 利用反射机制动态创建对象,无需修改工厂代码即可新增产品。
4.3 对象重复创建、性能冗余
问题描述:传统工厂每次调用都new新对象,高频调用场景下会产生大量临时对象,造成GC压力。
解决方案:
1. 无状态产品对象:通过静态Map缓存实例,全局复用,避免重复创建;
2. Spring场景:利用容器默认单例特性,自动复用产品实例;
3. 有状态对象:按需创建,结合对象池优化性能。
4.4 未知产品类型容错问题
问题描述:传入无效产品类型时,工厂抛出原生异常,提示不友好,程序健壮性差。
解决方案:
1. 增加参数校验、非空判断,提前拦截无效参数;
2. 自定义业务异常,替换原生报错,统一异常提示;
3. 设置默认兜底产品,避免空对象返回。
5. 高频面试:相似模式核心区分
工厂模式 vs 策略模式
- 工厂模式:关注对象创建,核心是解决「对象怎么来」的问题,统一对象生产、解耦创建逻辑;
- 策略模式:关注算法行为,核心是解决「行为怎么执行」的问题,支持算法动态替换、解耦业务分支。
工厂模式 vs 单例模式
- 工厂模式:专注对象创建管控,可生产多实例、多类型对象;
- 单例模式:专注对象实例唯一性,保证全局仅有一个实例。
6. 工厂模式在主流框架中的落地(面试高频)
6.1 Spring Framework
Spring核心容器就是典型的工厂模式落地:
BeanFactory:Spring顶层工厂接口,定义Bean统一创建、获取规范;
ApplicationContext:BeanFactory子接口,拓展企业级能力,是具体的高级工厂实现;
Spring通过工厂模式统一创建、托管所有Bean,业务代码无需手动创建对象。
6.2 Hibernate
SessionFactory:工厂接口,负责创建Session数据库会话对象,屏蔽连接创建细节,统一数据库操作实例生产。
6.3 JPA
EntityManagerFactory:工厂类,统一创建EntityManager实体管理器,实现持久化对象的统一创建与管理。
6.4 Apache 开源组件
Apache Commons:大量工具类使用静态工厂方法创建实例;
Apache POI:根据Excel版本不同,通过工厂创建HSSFWorkbook / XSSFWorkbook不同实例。
| 框架组件 | 对应工厂模式 | 核心依据 |
|---|---|---|
| Spring BeanFactory/ApplicationContext | 工厂方法模式(内含简单工厂逻辑) | 存在抽象工厂 + 多套具体上下文工厂,单一产品 Bean |
| Hibernate SessionFactory | 工厂方法模式 | 抽象工厂,仅生产 Session 单一产品 |
| JPA EntityManagerFactory | 工厂方法模式 | 多厂商具体工厂,只生产 EntityManager |
| Apache Commons 静态工具 | 简单工厂(静态工厂) | 静态方法统一创建,无分层工厂 |
| Apache POI WorkbookFactory | 简单工厂(静态工厂) | 静态方法分支判断生成不同 Workbook |
6.5 客户端如何简单辨认具体的工厂模式?
简单工厂模式:客户端一直使用同一个途径(统一工厂类)创建对象。
工厂方法模式:客户端通过不同的需求,使用不同的具体工厂实现类创建对象。
抽象工厂模式:客户端通过不同的需求,使用不同的具体工厂实现类创建对象,还可以获取到该产品族(具体工厂实现类)下的不同产品。
7. 核心总结
工厂模式的核心本质是解耦对象创建与业务使用,统一对象生产入口,拥抱开闭原则,彻底解决代码冗余、耦合严重、扩展性差的问题,三种模式适配不同业务场景,按需选择即可,无需过度设计:
1. 简单工厂:极简高效,适合产品固定、无需频繁扩展的简单场景,日常开发最常用;
2. 工厂方法:标准高扩展,适合单品频繁迭代、对代码规范和扩展性有要求的企业级场景;
3. 抽象工厂:高阶组件化,仅适合多系列、多配套的关联产品场景,杜绝滥用;
4. 核心原则:简单场景不强行封装,复杂场景按需升级,以「解耦、可维护、可扩展」为核心目标,避免过度设计。
更多推荐
所有评论(0)