目录
[1. 抽象产品(Product)](#1. 抽象产品(Product))
[2. 具体产品(Concrete Product)](#2. 具体产品(Concrete Product))
[3. 抽象工厂(Factory)](#3. 抽象工厂(Factory))
[4. 具体工厂(Concrete Factory)](#4. 具体工厂(Concrete Factory))
[1. 定义抽象产品(日志接口)](#1. 定义抽象产品(日志接口))
[2. 实现具体产品(文件日志、控制台日志)](#2. 实现具体产品(文件日志、控制台日志))
[3. 定义抽象工厂(日志工厂接口)](#3. 定义抽象工厂(日志工厂接口))
[4. 实现具体工厂(文件日志工厂、控制台日志工厂)](#4. 实现具体工厂(文件日志工厂、控制台日志工厂))
[5. 客户端调用(使用工厂创建产品)](#5. 客户端调用(使用工厂创建产品))
前言
作为Java开发者,我们日常编码中总会面临对象创建的场景。如果直接通过new关键字实例化对象,会导致代码耦合度偏高,后续需求迭代时修改成本激增。工厂方法模式作为创建型设计模式的核心成员,正是为解决对象创建与使用的解耦问题而生。本文将从定义、结构、实现、应用场景等维度,带你彻底吃透工厂方法模式,助力写出更灵活、可维护的Java代码。
一、什么是工厂方法模式
工厂方法模式(Factory Method Pattern)的核心定义:定义一个创建对象的接口(抽象工厂),让子类决定实例化哪个类(具体产品),使一个类的实例化延迟到其子类。简单来说,就是"把对象创建的活儿交给子类来做",通过抽象工厂约定创建逻辑,由具体工厂负责具体产品的实例化,彻底隔绝产品创建与产品使用的直接关联。
它是对"简单工厂模式"的优化升级------简单工厂模式通过一个工厂类集中创建所有产品,违背了"开闭原则"(新增产品需修改工厂代码),而工厂方法模式将工厂抽象化,新增产品时只需新增对应具体工厂,无需改动原有代码,完美契合开闭原则,是更具扩展性的创建方案。
二、工厂方法模式的核心结构
工厂方法模式包含4个核心角色,各角色职责清晰,协同完成对象创建与解耦,结合Java场景拆解如下:
1. 抽象产品(Product)
定义所有具体产品的公共接口或抽象类,规范产品的核心行为。它是工厂方法模式中产品的"顶层规范",确保所有具体产品都具备统一的功能,便于客户端统一调用。
2. 具体产品(Concrete Product)
抽象产品的具体实现类,是工厂方法模式最终要创建的对象。每个具体产品对应一个具体工厂,由具体工厂负责其实例化。
3. 抽象工厂(Factory)
定义创建产品的抽象方法,该方法返回抽象产品类型,不涉及具体产品的创建逻辑。抽象工厂可以是接口,也可以是抽象类,其核心职责是约定"如何创建产品",而非"创建哪种产品"。
4. 具体工厂(Concrete Factory)
抽象工厂的实现类,重写抽象工厂的创建方法,负责实例化具体产品。每个具体工厂对应一种具体产品,新增产品时,只需新增对应的具体产品类和具体工厂类即可。
三、Java实战:工厂方法模式代码实现
我们以"日志记录器"为例,实现工厂方法模式。需求:支持两种日志记录方式(文件日志、控制台日志),后续可灵活扩展数据库日志等新类型,且新增时不修改原有代码。
1. 定义抽象产品(日志接口)
java
/**
* 抽象产品:日志记录器接口
* 定义所有日志的公共行为
*/
public interface Logger {
// 日志记录方法
void log(String message);
}
2. 实现具体产品(文件日志、控制台日志)
java
/**
* 具体产品1:文件日志记录器
*/
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("文件日志:" + message);
}
}
/**
* 具体产品2:控制台日志记录器
*/
public class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("控制台日志:" + message);
}
}
3. 定义抽象工厂(日志工厂接口)
java
/**
* 抽象工厂:日志工厂接口
* 定义创建日志对象的抽象方法
*/
public interface LoggerFactory {
// 抽象工厂方法,返回抽象产品类型
Logger createLogger();
}
4. 实现具体工厂(文件日志工厂、控制台日志工厂)
java
/**
* 具体工厂1:文件日志工厂
* 负责创建文件日志对象
*/
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可在此处添加文件日志的初始化逻辑(如创建文件、配置路径等)
return new FileLogger();
}
}
/**
* 具体工厂2:控制台日志工厂
* 负责创建控制台日志对象
*/
public class ConsoleLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可在此处添加控制台日志的初始化逻辑
return new ConsoleLogger();
}
}
5. 客户端调用(使用工厂创建产品)
java
/**
* 客户端:使用工厂方法模式创建日志对象
*/
public class Client {
public static void main(String[] args) {
// 1. 创建具体工厂(可根据配置动态选择工厂,无需硬编码)
LoggerFactory factory = new ConsoleLoggerFactory();
// 2. 通过工厂创建产品(面向抽象产品编程,无需关注具体实现)
Logger logger = factory.createLogger();
// 3. 使用产品功能
logger.log("工厂方法模式实战演示");
// 切换为文件日志,只需修改具体工厂,无需改动其他代码
factory = new FileLoggerFactory();
logger = factory.createLogger();
logger.log("切换为文件日志记录");
}
}
运行结果
java
控制台日志:工厂方法模式实战演示
文件日志:切换为文件日志记录
扩展新产品(数据库日志)
若需新增数据库日志,只需新增具体产品和具体工厂,无需修改原有代码,完全符合开闭原则:
java
// 新增具体产品:数据库日志
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("数据库日志:" + message);
}
}
// 新增具体工厂:数据库日志工厂
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 数据库日志初始化逻辑(如连接数据库)
return new DatabaseLogger();
}
}
// 客户端调用新增产品,无需修改原有代码
LoggerFactory dbFactory = new DatabaseLoggerFactory();
Logger dbLogger = dbFactory.createLogger();
dbLogger.log("数据库日志记录");
四、工厂方法模式的应用场景
工厂方法模式适合以下Java开发场景,核心是解决"对象创建与使用解耦"和"灵活扩展"问题:
-
产品类型不确定,需灵活扩展:如上述日志案例,后续可能新增多种日志类型,工厂方法可快速适配,无需改动原有逻辑。
-
对象创建逻辑复杂:当对象创建需要初始化配置、依赖其他对象、处理异常等复杂逻辑时,可将这些逻辑封装在具体工厂中,简化客户端代码。
-
面向抽象编程,降低耦合:客户端只需面向抽象产品和抽象工厂编程,无需关注具体产品的实现细节,符合"依赖倒置原则"。
-
框架中的应用:Java主流框架中大量使用工厂方法模式,如Spring的BeanFactory(抽象工厂),通过getBean()方法(工厂方法)创建Bean实例,不同的BeanFactory实现类对应不同的Bean创建逻辑。
五、工厂方法模式的优缺点
优点
-
符合开闭原则:新增产品时,只需新增具体产品和具体工厂,无需修改原有代码,扩展性强。
-
解耦创建与使用:将对象创建逻辑封装在工厂中,客户端无需关注创建细节,只需使用产品。
-
符合依赖倒置原则:依赖抽象而非具体,客户端依赖抽象工厂和抽象产品,降低代码耦合度。
-
单一职责原则:每个具体工厂只负责创建一种具体产品,职责清晰,便于维护。
缺点
-
类数量激增:每新增一种产品,需对应新增一个具体产品类和一个具体工厂类,增加系统复杂度。
-
系统灵活性依赖抽象层:抽象工厂和抽象产品的设计需精准,若后续需修改抽象层,成本较高。
-
简单场景冗余:对于产品类型固定、无需扩展的简单场景,使用工厂方法会增加代码冗余,不如直接new对象简洁。
六、工厂方法模式与简单工厂模式的区别
很多Java开发者会混淆两者,核心区别在于"是否遵循开闭原则"和"工厂的职责范围":
| 对比维度 | 简单工厂模式 | 工厂方法模式 |
|---|---|---|
| 工厂数量 | 一个统一的工厂类 | 一个抽象工厂 + 多个具体工厂 |
| 开闭原则 | 违背:新增产品需修改工厂代码 | 遵循:新增产品只需新增工厂和产品 |
| 职责划分 | 工厂职责过重,负责所有产品创建 | 职责拆分,每个工厂只负责一种产品 |
| 扩展性 | 差,修改原有代码易引发风险 | 好,灵活扩展,无侵入式修改 |
七、总结
工厂方法模式的核心价值,是将对象的"创建权"与"使用权"分离,通过抽象层定义规范,让子类承担具体创建职责,从而实现代码解耦与灵活扩展。它是Java设计模式中"创建型模式"的基础,也是理解抽象工厂模式、建造者模式的前提。
在实际开发中,我们无需盲目使用工厂方法模式------对于简单场景,直接new对象更高效;但对于产品类型多变、创建逻辑复杂的场景,工厂方法模式能显著提升代码的可维护性和扩展性,尤其在框架开发中(如Spring、MyBatis),其应用随处可见。
作为Java学者,掌握工厂方法模式,不仅能写出更优雅的代码,更能理解主流框架的设计思想,为后续学习更复杂的设计模式打下坚实基础。