Java 设计模式精讲:工厂方法模式
Java 设计模式精讲:工厂方法模式
本篇教程将从零开始、由浅入深,用最通俗的语言、最完整的 Java 代码、最贴合实战的场景,结合七大设计原则深度拆解工厂方法模式,帮你彻底吃透这个设计模式,不仅会写,更懂为什么这么写,能在实际项目中灵活落地。
前言:为什么我们需要工厂模式?
在学习工厂方法之前,我们先看一个所有 Java 新手都会写的「坏代码」,这也是工厂模式诞生的核心原因。
假设我们要开发一个「手机销售系统」,需要创建华为、小米两种手机对象,直接调用它们的通话功能:
// 手机接口
public interface Phone {
void call(); // 通话功能
}
// 华为手机
public class HuaweiPhone implements Phone {
@Override
public void call() {
System.out.println("华为手机通话");
}
}
// 小米手机
public class XiaomiPhone implements Phone {
@Override
public void call() {
System.out.println("小米手机通话");
}
}
// 客户端(测试类)
public class Client {
public static void main(String[] args) {
// 直接new对象!耦合度极高
Phone huawei = new HuaweiPhone();
huawei.call();
Phone xiaomi = new XiaomiPhone();
xiaomi.call();
}
}
这段代码的致命问题(架构视角)
- 强耦合:客户端直接依赖具体的实现类(
HuaweiPhone/XiaomiPhone),一旦类名修改、构造器变更,客户端代码必须全部修改; - 无法扩展:如果新增苹果手机,客户端必须新增
new ApplePhone(),违背「扩展开放、修改关闭」; - 创建逻辑冗余:如果手机创建需要初始化参数、连接数据库、加载配置,所有客户端都要写重复的创建代码;
- 违反设计原则:完全依赖具体实现,不依赖抽象,不符合架构设计的核心思想。
工厂模式的核心价值:将「对象的创建」和「对象的使用」分离,客户端只负责使用对象,创建逻辑交给工厂,彻底解耦!
工厂模式分为三类:简单工厂模式(静态工厂)→ 工厂方法模式 → 抽象工厂模式,难度逐级递增。我们遵循「由浅入深」原则,先学基础,再深入核心的工厂方法模式。
第一章 设计基石:Java 七大设计原则(通俗精讲)
工厂方法模式是七大设计原则的完美实践,在讲解模式之前,我们必须先吃透这 7 个原则(架构师的核心准则),每个原则用通俗语言 + 极简代码讲解,后面会逐一对应工厂方法的实现。
1.1 单一职责原则(SRP)
核心:一个类 / 接口 / 方法,只负责一件事,职责单一,避免「全能类」。
✅ 好代码:手机类只做手机功能,工厂类只做创建对象。
❌ 坏代码:一个类既创建手机,又实现手机通话,还做销售逻辑。
1.2 开闭原则(OCP)
核心:对扩展开放,对修改关闭。新增功能时,不修改原有代码,只新增代码。
这是设计模式的第一原则,也是工厂方法模式的核心目标。
1.3 里氏替换原则(LSP)
核心:子类可以完全替换父类 / 接口,程序功能不受影响。
基于「多态」实现,所有实现类必须遵循父类的契约。
1.4 依赖倒置原则(DIP)
核心:依赖抽象,不依赖具体。
高层模块(客户端)不依赖低层模块(具体实现),两者都依赖抽象(接口 / 抽象类)。
1.5 接口隔离原则(ISP)
核心:接口要小而专,不要大而全。避免实现类被迫实现不需要的方法。
1.6 迪米特法则(LoD)
核心:最少知道原则。一个对象只和「直接朋友」交互,不跟「陌生人」说话,减少类之间的依赖。
1.7 合成复用原则(CRP)
核心:优先使用组合 / 聚合,而不是继承实现复用。
继承会强耦合,组合更灵活,是架构设计的首选复用方式。
第二章 入门铺垫:简单工厂模式(静态工厂)
工厂方法模式是简单工厂的升级优化版,我们先学简单工厂,找到它的缺陷,自然就能理解工厂方法的必要性。
2.1 简单工厂定义
简单工厂(静态工厂):定义一个工厂类,通过静态方法接收参数,创建不同的产品对象。
它不属于 GOF23 种设计模式,但它是工厂方法的基础。
2.2 简单工厂代码实现(手机案例)
// 1. 抽象产品:手机接口
public interface Phone {
void call();
}
// 2. 具体产品:华为手机
public class HuaweiPhone implements Phone {
@Override
public void call() {
System.out.println("华为手机:鸿蒙系统通话");
}
}
// 3. 具体产品:小米手机
public class XiaomiPhone implements Phone {
@Override
public void call() {
System.out.println("小米手机:MIUI系统通话");
}
}
// 4. 简单工厂类(核心)
public class SimplePhoneFactory {
// 静态方法:根据参数创建手机
public static Phone createPhone(String type) {
if ("huawei".equals(type)) {
return new HuaweiPhone();
} else if ("xiaomi".equals(type)) {
return new XiaomiPhone();
} else {
throw new IllegalArgumentException("不支持的手机类型");
}
}
}
// 5. 客户端
public class Client {
public static void main(String[] args) {
// 客户端只调用工厂,不直接new对象
Phone huawei = SimplePhoneFactory.createPhone("huawei");
huawei.call();
Phone xiaomi = SimplePhoneFactory.createPhone("xiaomi");
xiaomi.call();
}
}
2.3 简单工厂的优点
- 客户端不再直接 new 对象,解耦了「创建与使用」;
- 统一管理对象创建逻辑,复用性强。
2.4 简单工厂的致命缺陷(违背开闭原则)
如果我们新增苹果手机,必须修改SimplePhoneFactory的if-else代码:
// 新增苹果手机类
public class ApplePhone implements Phone {
@Override
public void call() {
System.out.println("苹果手机:iOS系统通话");
}
}
// 修改工厂类!违背开闭原则
public class SimplePhoneFactory {
public static Phone createPhone(String type) {
if ("huawei".equals(type)) {
return new HuaweiPhone();
} else if ("xiaomi".equals(type)) {
return new XiaomiPhone();
} else if ("apple".equals(type)) { // 新增代码
return new ApplePhone();
} else {
throw new IllegalArgumentException("不支持的手机类型");
}
}
}
❌ 核心问题:扩展产品必须修改工厂原有代码,直接违反开闭原则!
这就是简单工厂的天花板,想要解决这个问题,就需要工厂方法模式。
第三章 核心精讲:工厂方法设计模式
3.1 工厂方法定义(官方 + 通俗)
GOF 官方定义:定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
通俗解释:
- 不再用一个工厂生产所有产品,而是一个产品对应一个专属工厂;
- 定义抽象工厂接口,具体工厂实现接口,各自生产对应的产品;
- 扩展新产品时,只新增产品类 + 工厂类,不修改原有任何代码,完美遵循开闭原则。
3.2 工厂方法的四大核心角色
工厂方法是标准的四层结构,架构清晰,职责明确:
| 角色 | 英文 | 作用 | 手机案例对应 |
|---|---|---|---|
| 抽象产品 | Product | 定义所有产品的公共接口 / 抽象类 | Phone接口 |
| 具体产品 | ConcreteProduct | 实现抽象产品,具体的业务对象 | HuaweiPhone/XiaomiPhone/ApplePhone |
| 抽象工厂 | Factory | 定义创建产品的接口,核心工厂方法 | PhoneFactory接口 |
| 具体工厂 | ConcreteFactory | 实现抽象工厂,创建对应的具体产品 | HuaweiFactory/XiaomiFactory/AppleFactory |
3.3 工厂方法完整代码实现(Java 实战)
我们用手机案例重构,严格遵循四大角色,代码可直接复制运行:
第一步:定义抽象产品(Phone 接口)
/**
* 抽象产品:手机接口
* 定义所有手机的公共行为
*/
public interface Phone {
// 通话功能
void call();
// 发送短信
void sendMessage();
}
第二步:定义具体产品(实现 Phone 接口)
/**
* 具体产品:华为手机
*/
public class HuaweiPhone implements Phone {
@Override
public void call() {
System.out.println("【华为手机】鸿蒙系统 - 高清通话");
}
@Override
public void sendMessage() {
System.out.println("【华为手机】鸿蒙系统 - 5G短信");
}
}
/**
* 具体产品:小米手机
*/
public class XiaomiPhone implements Phone {
@Override
public void call() {
System.out.println("【小米手机】MIUI系统 - 高清通话");
}
@Override
public void sendMessage() {
System.out.println("【小米手机】MIUI系统 - 5G短信");
}
}
/**
* 具体产品:苹果手机(新增产品,无需修改原有代码)
*/
public class ApplePhone implements Phone {
@Override
public void call() {
System.out.println("【苹果手机】iOS系统 - 高清通话");
}
@Override
public void sendMessage() {
System.out.println("【苹果手机】iOS系统 - iMessage短信");
}
}
第三步:定义抽象工厂(PhoneFactory 接口)
工厂方法的核心:抽象工厂定义创建产品的方法,不具体实现!
/**
* 抽象工厂:手机工厂接口
* 定义工厂方法:创建手机
*/
public interface PhoneFactory {
// 工厂方法:返回抽象产品,不依赖具体产品
Phone createPhone();
}
第四步:定义具体工厂(实现 PhoneFactory)
每个产品对应一个专属工厂,只生产自己的产品:
/**
* 具体工厂:华为工厂 → 只生产华为手机
*/
public class HuaweiFactory implements PhoneFactory {
@Override
public Phone createPhone() {
// 可以添加复杂的创建逻辑:初始化、配置加载、依赖注入
return new HuaweiPhone();
}
}
/**
* 具体工厂:小米工厂 → 只生产小米手机
*/
public class XiaomiFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new XiaomiPhone();
}
}
/**
* 具体工厂:苹果工厂 → 只生产苹果手机(新增工厂,无修改)
*/
public class AppleFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new ApplePhone();
}
}
第五步:客户端调用(核心:依赖抽象,不依赖具体)
/**
* 客户端:使用工厂方法创建对象
* 只依赖抽象接口,不依赖任何具体实现类!
*/
public class FactoryMethodClient {
public static void main(String[] args) {
// 1. 创建华为工厂(抽象工厂引用具体工厂)
PhoneFactory huaweiFactory = new HuaweiFactory();
Phone huaweiPhone = huaweiFactory.createPhone();
huaweiPhone.call();
huaweiPhone.sendMessage();
System.out.println("------------------------");
// 2. 创建小米工厂
PhoneFactory xiaomiFactory = new XiaomiFactory();
Phone xiaomiPhone = xiaomiFactory.createPhone();
xiaomiPhone.call();
xiaomiPhone.sendMessage();
System.out.println("------------------------");
// 3. 新增苹果手机:只新增类,不修改原有代码!
PhoneFactory appleFactory = new AppleFactory();
Phone applePhone = appleFactory.createPhone();
applePhone.call();
applePhone.sendMessage();
}
}
运行结果
【华为手机】鸿蒙系统 - 高清通话
【华为手机】鸿蒙系统 - 5G短信
------------------------
【小米手机】MIUI系统 - 高清通话
【小米手机】MIUI系统 - 5G短信
------------------------
【苹果手机】iOS系统 - 高清通话
【苹果手机】iOS系统 - iMessage短信
3.4 工厂方法的核心特性
- 延迟实例化:对象的创建由具体工厂决定,客户端不关心创建细节;
- 完全解耦:客户端只依赖抽象接口,与具体实现无关;
- 完美扩展:新增产品 = 新增产品类 + 新增工厂类,零修改原有代码。
第四章 深度契合:工厂方法与七大设计原则(架构师核心分析)
这是本章最核心、最干货的部分!我们逐一对应七大设计原则,结合上面的代码,证明工厂方法是「设计原则的最佳实践」。
4.1 遵循单一职责原则(SRP)
✅ 代码佐证:
- 具体产品(
HuaweiPhone):只实现手机的通话、短信功能,职责单一; - 具体工厂(
HuaweiFactory):只负责创建华为手机,职责单一; - 客户端:只负责使用对象,不参与创建。
每个类只做一件事,没有「全能类」,完全符合单一职责。
4.2 遵循开闭原则(OCP)
✅ 代码佐证:
新增苹果手机时,我们没有修改任何原有代码,只新增了ApplePhone和AppleFactory两个类,客户端直接调用即可。
对扩展开放,对修改关闭,这是工厂方法最核心的优势,彻底解决了简单工厂的缺陷。
4.3 遵循里氏替换原则(LSP)
✅ 代码佐证:
// 抽象工厂引用具体工厂,子类完全替换父类
PhoneFactory factory = new HuaweiFactory();
// 替换为小米工厂,程序功能不受影响
factory = new XiaomiFactory();
Phone phone = factory.createPhone();
所有具体工厂都实现PhoneFactory接口,具体产品都实现Phone接口,子类可以无缝替换父类,程序逻辑不变。
4.4 遵循依赖倒置原则(DIP)
✅ 代码佐证:
客户端代码只依赖抽象接口:
- 依赖
PhoneFactory(抽象工厂),不依赖HuaweiFactory(具体工厂); - 依赖
Phone(抽象产品),不依赖HuaweiPhone(具体产品)。
高层模块(客户端)和低层模块(具体实现)都依赖抽象,不依赖具体,彻底解耦。
4.5 遵循接口隔离原则(ISP)
✅ 代码佐证:
Phone接口只定义call()、sendMessage()两个核心方法,小而专;PhoneFactory接口只定义createPhone()一个工厂方法,无冗余方法;- 实现类不需要强制实现任何不需要的方法,接口设计极简。
4.6 遵循迪米特法则(LoD)
✅ 代码佐证:
客户端的「直接朋友」只有抽象工厂 + 抽象产品,完全不知道具体产品的创建细节、构造器、初始化逻辑。
客户端不与「陌生人」(具体实现类的内部逻辑)交互,最少知道,依赖最少。
4.7 遵循合成复用原则(CRP)
✅ 代码佐证:
客户端通过组合工厂对象(PhoneFactory factory = new HuaweiFactory())实现对象创建,而不是通过继承工厂类来复用创建逻辑。
组合比继承更灵活,无强耦合,符合架构设计的复用准则。
第五章 辩证分析:工厂方法的优点与局限性(架构视角)
作为架构师,我们不能只讲优点,必须客观分析模式的适用边界,避免过度设计。
5.1 工厂方法的核心优点(企业级架构必备)
- 彻底解耦:对象创建与使用分离,客户端无需关心创建细节;
- 可扩展性拉满:遵循开闭原则,产品扩展零成本;
- 代码可读性 / 可维护性极强:四层结构清晰,职责明确,团队协作无压力;
- 符合设计原则:完美契合七大原则,是架构级代码的标准;
- 多态性:基于接口编程,方便替换产品实现,适配不同业务场景;
- 统一创建规范:复杂对象的初始化逻辑(如配置加载、依赖注入)可以封装在工厂中,全局复用。
5.2 工厂方法的局限性(客观存在)
- 类数量爆炸:一个产品对应一个工厂,产品越多,类文件越多(比如 10 个产品 = 10 个工厂类);
- 系统复杂度提升:增加了抽象层,新手理解成本略高;
- 仅支持单一产品结构:工厂方法只能生产一种类型的产品(如只能生产手机,不能同时生产手机 + 耳机),多产品族需要抽象工厂模式;
- 不适合简单对象:如果对象创建无逻辑(直接 new),使用工厂方法属于过度设计。
5.3 架构师建议:什么时候用工厂方法?
- 产品需要频繁扩展,要求严格遵循开闭原则;
- 对象创建逻辑复杂(需要初始化、加载配置、连接资源);
- 客户端不关心对象如何创建,只需要使用对象;
- 框架 / 组件设计,需要定义统一的对象创建规范;
- 企业级项目,追求代码解耦、可维护、可扩展。
第六章 横向对比:简单工厂 vs 工厂方法 vs 抽象工厂
为了让你彻底区分三种工厂模式,我用架构师视角的表格总结:
| 对比维度 | 简单工厂(静态工厂) | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|---|
| 核心思想 | 一个工厂生产所有产品 | 一个工厂生产一种产品 | 一个工厂生产一族产品 |
| 开闭原则 | ❌ 违背(修改工厂) | ✅ 遵循(新增类) | ✅ 遵循 |
| 产品结构 | 单一产品 | 单一产品等级 | 多产品族(手机 + 耳机 + 充电器) |
| 代码复杂度 | 低 | 中 | 高 |
| 类数量 | 少 | 中 | 多 |
| 适用场景 | 产品少,不常扩展 | 单一产品,常扩展 | 多产品族,常扩展 |
| 设计原则 | 部分遵循 | 完全遵循 | 完全遵循 |
一句话总结:
- 小项目、产品固定 → 简单工厂;
- 单一产品、需要扩展 → 工厂方法(最常用);
- 多产品族、复杂业务 → 抽象工厂。
第七章 源码洞察:JDK/Spring 中工厂方法的经典应用
学习设计模式的最终目的是看懂源码、落地项目。工厂方法在 Java 生态中无处不在,我带你拆解两个最经典的源码案例:
7.1 JDK 源码:Collection 的 iterator () 方法(最经典)
JDK 集合框架是工厂方法模式的教科书级实现:
- 抽象产品:
Iterator<E>(迭代器接口); - 具体产品:
ArrayList.Itr、HashSet.Itr(迭代器实现类); - 抽象工厂:
Collection<E>(集合接口,定义iterator()工厂方法); - 具体工厂:
ArrayList、HashSet(实现 Collection,创建对应的迭代器)。
源码简化版:
// 抽象工厂:Collection
public interface Collection<E> {
// 工厂方法:创建迭代器(抽象产品)
Iterator<E> iterator();
}
// 具体工厂:ArrayList
public class ArrayList<E> implements Collection<E> {
// 实现工厂方法,创建具体产品
@Override
public Iterator<E> iterator() {
return new Itr();
}
// 具体产品:迭代器实现类
private class Itr implements Iterator<E> {
// 迭代器逻辑
}
}
// 客户端使用
public class JdkClient {
public static void main(String[] args) {
// 抽象工厂引用具体工厂
Collection<String> list = new ArrayList<>();
// 调用工厂方法,获取抽象产品
Iterator<String> iterator = list.iterator();
}
}
✅ 完全符合工厂方法的四大角色,这就是 JDK 的设计精髓!
7.2 Spring 源码:FactoryBean 接口
Spring 框架是工厂方法的重度使用者,FactoryBean是 Spring 自定义 Bean 的核心接口:
- 抽象工厂:
FactoryBean<T>; - 具体工厂:自定义
UserFactoryBean; - 抽象产品:
Object/ 业务 Bean; - 工厂方法:
getObject()。
Spring 实战代码:
// 抽象工厂:Spring的FactoryBean
public interface FactoryBean<T> {
// 工厂方法:创建Bean对象
T getObject() throws Exception;
}
// 具体产品:用户对象
public class User {
private String name;
// getter/setter
}
// 具体工厂:用户工厂
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() {
// 复杂的Bean创建逻辑
User user = new User();
user.setName("工厂方法创建的用户");
return user;
}
}
// 客户端:Spring容器自动调用工厂方法
@SpringBootApplication
public class SpringClient {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringClient.class);
// 获取工厂创建的Bean
User user = context.getBean(User.class);
System.out.println(user.getName());
}
}
Spring 用工厂方法实现了Bean 的灵活创建,是框架设计的核心。
第八章 实战优化:解决工厂方法的「类爆炸」问题
工厂方法的唯一缺点是「类太多」,架构师在项目中会用3 种优化方案,既保留开闭原则,又减少类数量:
8.1 方案 1:反射 + 配置文件(无具体工厂)
通过反射动态创建产品,不需要为每个产品写工厂类,彻底解决类爆炸:
// 抽象工厂
public interface PhoneFactory {
Phone createPhone();
}
// 通用工厂:反射实现
public class ReflectPhoneFactory implements PhoneFactory {
// 产品全类名(从配置文件读取)
private Class<? extends Phone> phoneClass;
public ReflectPhoneFactory(Class<? extends Phone> phoneClass) {
this.phoneClass = phoneClass;
}
@Override
public Phone createPhone() {
try {
// 反射创建对象
return phoneClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("创建失败");
}
}
}
// 客户端
public class OptimizeClient {
public static void main(String[] args) {
// 一个通用工厂,创建所有产品
PhoneFactory factory = new ReflectPhoneFactory(HuaweiPhone.class);
Phone phone = factory.createPhone();
phone.call();
}
}
8.2 方案 2:抽象类代替接口(复用公共逻辑)
用抽象工厂类代替接口,封装公共创建逻辑,减少重复代码:
// 抽象工厂类(非接口)
public abstract class AbstractPhoneFactory {
// 公共方法:所有工厂复用
public void checkQuality() {
System.out.println("手机质量检测");
}
// 抽象工厂方法
public abstract Phone createPhone();
}
8.3 方案 3:Spring 注解(零工厂类)
直接用 Spring 的@Bean注解,让 Spring 容器作为工厂,完全消除手动工厂类:
@Configuration
public class PhoneConfig {
@Bean
public Phone huaweiPhone() {
return new HuaweiPhone();
}
@Bean
public Phone xiaomiPhone() {
return new XiaomiPhone();
}
}
这是企业级项目最常用的优化方案。
第九章 避坑指南:工厂方法的常见误区
作为架构师,我总结了新手最容易踩的 5 个坑:
9.1 误区 1:混淆简单工厂和工厂方法
- 简单工厂:静态方法,一个工厂生产所有产品,违背开闭;
- 工厂方法:接口 + 子类,一个工厂生产一种产品,遵循开闭。
9.2 误区 2:抽象工厂必须是接口
抽象工厂可以是抽象类,只要定义工厂方法即可,灵活即可。
9.3 误区 3:所有对象都用工厂方法创建
简单对象(无创建逻辑)直接new,过度设计会让代码更复杂。
9.4 误区 4:工厂方法可以生产多产品
工厂方法仅支持单一产品,多产品族用抽象工厂。
9.5 误区 5:客户端依赖具体工厂
客户端必须用抽象工厂引用具体工厂,否则失去解耦意义。
第十章 架构升华:工厂方法的设计思想与核心价值
10.1 工厂方法的核心思想
面向抽象编程,延迟实例化,解耦创建与使用。
它不是单纯的「创建对象」,而是架构设计的解耦思想:将变化的部分(产品实现)封装起来,不变的部分(抽象接口)稳定下来,让系统更灵活、更健壮。
10.2 工厂方法的架构价值
- 是企业级代码的基础:所有主流框架(Spring、MyBatis、Dubbo)都基于工厂方法;
- 是设计原则的落地载体:完美实践开闭、依赖倒置等核心原则;
- 是代码优雅的标准:让代码从「新手级」升级为「架构级」;
- 是团队协作的规范:统一对象创建规范,降低沟通成本。
总结(万字核心回顾)
本篇教程从新手痛点→设计原则→简单工厂→工厂方法→源码→实战→优化,由浅入深彻底讲解了工厂方法模式,核心要点总结:
- 核心定义:一个产品对应一个专属工厂,抽象工厂定义接口,具体工厂实现创建,延迟实例化;
- 四大角色:抽象产品、具体产品、抽象工厂、具体工厂;
- 核心优势:完美遵循开闭原则,彻底解耦对象创建与使用,符合七大设计原则;
- 适用场景:单一产品、需要扩展、对象创建复杂的企业级项目;
- 源码应用:JDK Collection、Spring FactoryBean 都是经典实现;
- 优化方案:反射、抽象类、Spring 注解解决类爆炸问题。
工厂方法模式是 Java 设计模式的入门必学、工作必用的核心模式,也是你从编程新手成长为架构师的必经之路。掌握它,你不仅能写出优雅的代码,更能读懂所有主流框架的设计精髓!
浙公网安备 33010602011771号