工厂模式:解耦对象创建与使用的设计模式
一、模式核心:封装对象创建逻辑,客户端无需关心具体实现
在软件开发中,当创建对象的逻辑复杂或频繁变化时,直接在客户端代码中 new 对象会导致耦合度高、难以维护。例如,创建不同类型的日志记录器(文件日志、数据库日志)时,客户端若直接依赖具体类,后续新增日志类型需修改所有调用处。
工厂模式(Factory Pattern) 通过引入一个工厂类,将对象的创建逻辑封装起来,客户端只需通过工厂类获取对象,无需知道对象的具体创建过程。核心解决:
- 解耦创建与使用:客户端与具体产品类解耦,专注于业务逻辑。
- 集中管理创建逻辑:对象创建规则统一在工厂类中维护,便于修改和扩展。
- 符合开闭原则:新增产品类型时,只需扩展工厂类,无需修改现有客户端代码。
核心角色
- 抽象产品(Product) :定义产品的公共接口(如日志记录器的
log()
方法)。 - 具体产品(Concrete Product) :实现抽象产品接口,如
FileLogger
、DatabaseLogger
。 - 工厂类(Factory):负责创建具体产品实例,返回抽象产品类型。
核心思想与 UML 类图

二、核心实现:日志记录器工厂
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);
}
}
数据库日志记录器
java
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("数据库日志:" + message);
}
}
3. 实现工厂类
java
public class LoggerFactory {
// 根据类型创建日志记录器
public static Logger createLogger(String type) {
switch (type.toUpperCase()) {
case "FILE":
return new FileLogger();
case "DATABASE":
return new DatabaseLogger();
default:
throw new IllegalArgumentException("不支持的日志类型:" + type);
}
}
}
4. 客户端调用
java
public class ClientDemo {
public static void main(String[] args) {
// 通过工厂获取文件日志记录器
Logger fileLogger = LoggerFactory.createLogger("file");
fileLogger.log("系统启动");
// 通过工厂获取数据库日志记录器
Logger dbLogger = LoggerFactory.createLogger("database");
dbLogger.log("用户登录");
}
}
输出结果:
plaintext
文件日志:系统启动
数据库日志:用户登录
三、扩展:参数化配置实现动态工厂
为避免硬编码产品类型,可通过配置文件(如config.properties
)动态指定产品类,提升灵活性。
1. 创建配置文件(src/config.properties)
properties
logger.type=file
2. 修改工厂类读取配置
java
import java.io.IOException;
import java.util.Properties;
public class LoggerFactory {
private static final String CONFIG_FILE = "config.properties";
public static Logger createLogger() {
try {
// 读取配置文件
Properties prop = new Properties();
prop.load(LoggerFactory.class.getClassLoader().getResourceAsStream(CONFIG_FILE));
String type = prop.getProperty("logger.type");
// 根据配置创建产品
switch (type.toUpperCase()) {
case "FILE":
return new FileLogger();
case "DATABASE":
return new DatabaseLogger();
default:
throw new IllegalArgumentException("配置错误:未知日志类型");
}
} catch (IOException e) {
throw new RuntimeException("加载配置失败", e);
}
}
}
3. 客户端简化调用
java
public class ClientDemo {
public static void main(String[] args) {
Logger logger = LoggerFactory.createLogger(); // 自动根据配置创建
logger.log("动态加载的日志记录器");
}
}
四、工厂模式 vs 抽象工厂模式
对比维度 | 工厂模式 | 抽象工厂模式 |
---|---|---|
处理对象 | 单一产品类型(如 Logger) | 产品族(如 Logger + LogAnalyzer) |
扩展性 | 新增产品需修改工厂类 | 新增产品族只需扩展新工厂 |
复杂度 | 简单,适合小型场景 | 复杂,适合多产品族的大型系统 |
典型场景 | 单一类型对象创建(如日志、数据库连接) | 跨平台组件(如 Windows/Linux 界面组件) |
五、适用场景
场景 | 示例 | 优势 |
---|---|---|
对象创建逻辑复杂 | 涉及参数校验、资源初始化的对象 | 封装复杂逻辑,避免客户端臃肿 |
多类型产品切换 | 不同环境下使用不同实现(如测试 / 生产环境) | 客户端无需修改,通过工厂动态切换 |
遵循迪米特法则 | 减少客户端与具体类的直接依赖 | 降低耦合度,提升可维护性 |
六、总结
工厂模式通过 "封装创建,暴露接口" 的设计,使客户端代码更简洁、可维护性更高。它是创建型模式的基础,在 Java 集合框架(如Calendar.getInstance()
)、Spring 框架(Bean 工厂)中广泛应用。
扩展思考:
- 工厂模式有哪些变种?(如静态工厂、工厂方法模式)
- 如何结合反射机制进一步优化工厂类?