文章目录
- 前言
- 一、概念
- 二、核心思想
- 三、Java代码实现
-
- [1. 定义抽象产品(日志记录器接口)](#1. 定义抽象产品(日志记录器接口))
- [2. 定义具体产品(文件日志/数据库日志)](#2. 定义具体产品(文件日志/数据库日志))
- [3. 定义抽象工厂(日志工厂接口)](#3. 定义抽象工厂(日志工厂接口))
- [4. 定义具体工厂(文件日志工厂/数据库日志工厂)](#4. 定义具体工厂(文件日志工厂/数据库日志工厂))
- [5. 客户端使用代码](#5. 客户端使用代码)
- [6. 扩展:新增Redis日志(符合开闭原则)](#6. 扩展:新增Redis日志(符合开闭原则))
- 四、优缺点
-
- [1. 优点](#1. 优点)
- [2. 缺点](#2. 缺点)
- 五、应用场景
- 六、注意事项
- 总结
前言
在AI时代,代码的编写可以被大模型辅助甚至替代,但程序员真正的核心竞争力是技术思维------设计模式这类沉淀了数十年的"内功心法",决定了代码的可维护性、扩展性和稳定性,是AI无法完全替代的核心能力。工厂方法模式作为创建型模式的核心,解决了"对象创建与业务逻辑耦合"的问题,是解耦对象创建的基础范式。
一、概念
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,定义了一个创建对象的接口,但让实现这个接口的子类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行,核心是"将对象的创建权交给子类"。
简单来说,工厂方法模式把"创建什么对象"的判断逻辑,从主业务逻辑中抽离,交给专门的工厂类处理,让主程序只关注"使用对象",而非"创建对象"。
二、核心思想
- 抽象产品:定义产品的通用接口/抽象类,规范产品的核心行为;
- 具体产品:实现抽象产品接口,是最终被创建的对象;
- 抽象工厂:定义创建产品的抽象方法,声明返回抽象产品类型;
- 具体工厂:实现抽象工厂的创建方法,返回具体产品实例,决定创建哪种产品。
工厂方法模式的核心本质是**"开闭原则"的体现**------新增产品时,无需修改原有工厂和业务代码,只需新增"具体产品+具体工厂",符合"对扩展开放、对修改关闭"。
三、Java代码实现
以"日志记录器"场景为例:系统需要支持文件日志、数据库日志两种记录方式,后续可能扩展Redis日志,用工厂方法模式实现解耦。
1. 定义抽象产品(日志记录器接口)
java
/**
* 抽象产品:日志记录器接口
* 定义所有日志记录器的通用行为
*/
public interface Logger {
// 日志记录方法
void log(String message);
}
2. 定义具体产品(文件日志/数据库日志)
java
/**
* 具体产品:文件日志记录器
*/
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("【文件日志】:" + message);
}
}
/**
* 具体产品:数据库日志记录器
*/
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("【数据库日志】:" + message);
}
}
3. 定义抽象工厂(日志工厂接口)
java
/**
* 抽象工厂:日志记录器工厂接口
* 定义创建日志记录器的抽象方法
*/
public interface LoggerFactory {
// 创建日志记录器的工厂方法
Logger createLogger();
}
4. 定义具体工厂(文件日志工厂/数据库日志工厂)
java
/**
* 具体工厂:文件日志工厂
* 负责创建文件日志记录器实例
*/
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可在此添加文件日志器的初始化逻辑(如创建文件、配置路径)
return new FileLogger();
}
}
/**
* 具体工厂:数据库日志工厂
* 负责创建数据库日志记录器实例
*/
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可在此添加数据库日志器的初始化逻辑(如建立数据库连接)
return new DatabaseLogger();
}
}
5. 客户端使用代码
java
/**
* 客户端:业务逻辑层
* 只关注使用日志器,不关注创建细节
*/
public class Client {
public static void main(String[] args) {
// 1. 创建文件日志工厂
LoggerFactory fileFactory = new FileLoggerFactory();
// 2. 通过工厂创建文件日志器
Logger fileLogger = fileFactory.createLogger();
fileLogger.log("用户登录成功");
// 1. 创建数据库日志工厂
LoggerFactory dbFactory = new DatabaseLoggerFactory();
// 2. 通过工厂创建数据库日志器
Logger dbLogger = dbFactory.createLogger();
dbLogger.log("用户下单失败");
}
}
输出结果:
【文件日志】:用户登录成功
【数据库日志】:用户下单失败
6. 扩展:新增Redis日志(符合开闭原则)
java
// 1. 新增具体产品:Redis日志记录器
public class RedisLogger implements Logger {
@Override
public void log(String message) {
System.out.println("【Redis日志】:" + message);
}
}
// 2. 新增具体工厂:Redis日志工厂
public class RedisLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new RedisLogger();
}
}
// 3. 客户端使用(无需修改原有代码)
public class Client {
public static void main(String[] args) {
LoggerFactory redisFactory = new RedisLoggerFactory();
Logger redisLogger = redisFactory.createLogger();
redisLogger.log("系统启动完成");
}
}
四、优缺点
1. 优点
- 解耦创建与使用:业务逻辑只关注产品的使用,创建逻辑由工厂类负责,代码职责更清晰;
- 符合开闭原则:新增产品时,只需新增"具体产品+具体工厂",无需修改原有代码;
- 提高代码可维护性:产品创建逻辑集中在工厂类,后续修改创建规则(如初始化参数)只需改工厂,无需改所有使用处;
- 隐藏产品细节:客户端仅依赖抽象产品和抽象工厂,无需知道具体产品的实现细节。
2. 缺点
- 类数量膨胀:每新增一个产品,需同时新增具体产品类和具体工厂类,系统类数量会成倍增加;
- 增加系统复杂度:简单场景下使用工厂方法,会引入额外的抽象层和工厂类,增加理解成本;
- 抽象层设计难度高:若抽象产品/工厂设计不合理,后续扩展可能需要修改抽象层,违背开闭原则。
五、应用场景
工厂方法模式适用于对象创建逻辑复杂、产品类型易扩展的场景:
- 框架扩展场景 :Java集合的
Collection.iterator()方法(子类ArrayList/HashSet实现自己的迭代器工厂); - 日志/存储扩展:如示例中的多类型日志记录、多数据源(MySQL/Oracle/Redis)连接创建;
- 插件化开发:系统支持多种插件,每种插件对应一个工厂类,新增插件只需新增插件类和工厂类;
- 复杂对象创建:对象创建需要初始化参数、资源加载等复杂逻辑,将这些逻辑封装在工厂中;
- 跨平台适配:如不同操作系统的UI组件(WindowsButton/LinuxButton),由对应工厂创建。
六、注意事项
- 避免过度设计:简单场景(产品类型固定、创建逻辑简单)无需使用工厂方法,直接new更简洁;
- 抽象层设计:抽象产品/工厂需提炼通用行为,避免包含具体产品的特有方法,否则客户端仍需强转;
- 工厂的单一职责:每个具体工厂只负责创建一种产品,避免一个工厂创建多种产品导致逻辑混乱;
- 与简单工厂的区别:简单工厂是"一个工厂创建所有产品"(违背开闭),工厂方法是"一个工厂对应一个产品"(符合开闭)。
总结
- 工厂方法模式核心是将对象创建推迟到子类,通过"抽象产品+抽象工厂"解耦创建与使用,符合开闭原则;
- 优势是扩展灵活、职责清晰,缺点是类数量膨胀,需根据场景选择(产品易扩展时优先使用);
- Java标准库中
Collection.iterator()是工厂方法的经典应用,理解其设计思路可举一反三。