工厂方法模式 (Factory Method Pattern)
概述
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。
工厂方法模式通过将对象的创建与使用分离,提供了一种更灵活、更可扩展的方式来创建对象,特别适合那些需要根据不同条件创建不同类型对象的场景。
核心要点
- 创建与使用分离:客户端代码不需要知道具体产品的创建细节
- 封装变化:将对象创建的变化封装在工厂类中
- 符合开闭原则:新增产品类型时,只需要新增对应的工厂子类,不需要修改现有代码
- 多态性:通过抽象接口实现不同产品的创建
应用场景
- 当一个类不知道它所必须创建的对象的类的时候
- 当一个类希望由子类来指定它所创建的对象的时候
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且希望将哪一个帮助子类是代理者这一信息局部化的时候
- 需要系统独立于产品的创建、组合和表示时
结构
工厂方法模式包含以下角色:
- 产品(Product):定义工厂方法所创建的对象的接口
- 具体产品(Concrete Product):实现产品接口
- 创建者(Creator):声明工厂方法,该方法返回一个产品类型的对象
- 具体创建者(Concrete Creator):实现工厂方法,返回具体产品的实例
实现示例
1. 产品接口和具体产品
java
// 产品接口
public interface Product {
void use();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}2. 创建者接口和具体创建者
java
// 创建者抽象类
public abstract class Creator {
// 工厂方法
public abstract Product factoryMethod();
// 其他业务方法
public void someOperation() {
// 创建产品
Product product = factoryMethod();
// 使用产品
product.use();
}
}
// 具体创建者A
public class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具体创建者B
public class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}3. 客户端使用
java
public class Client {
public static void main(String[] args) {
// 创建具体创建者A
Creator creatorA = new ConcreteCreatorA();
creatorA.someOperation(); // 输出: 使用产品A
// 创建具体创建者B
Creator creatorB = new ConcreteCreatorB();
creatorB.someOperation(); // 输出: 使用产品B
}
}实际应用示例:日志记录器
下面是一个更贴近实际应用的示例,展示如何使用工厂方法模式创建不同类型的日志记录器:
产品接口和具体产品
java
// 日志记录器接口
public interface Logger {
void log(String message);
}
// 文件日志记录器
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("写入日志到文件: " + message);
}
}
// 控制台日志记录器
public class ConsoleLogger 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);
}
}创建者接口和具体创建者
java
// 日志记录器工厂抽象类
public abstract class LoggerFactory {
// 工厂方法
public abstract Logger createLogger();
}
// 文件日志记录器工厂
public class FileLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
// 可能有一些初始化工作,如创建文件、设置权限等
return new FileLogger();
}
}
// 控制台日志记录器工厂
public class ConsoleLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
// 数据库日志记录器工厂
public class DatabaseLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
// 可能有一些初始化工作,如建立数据库连接等
return new DatabaseLogger();
}
}客户端使用
java
public class Client {
public static void main(String[] args) {
// 可以根据配置或运行时条件选择不同的工厂
LoggerFactory factory;
String config = "file"; // 可以从配置文件读取
if (config.equals("file")) {
factory = new FileLoggerFactory();
} else if (config.equals("console")) {
factory = new ConsoleLoggerFactory();
} else {
factory = new DatabaseLoggerFactory();
}
// 创建日志记录器
Logger logger = factory.createLogger();
logger.log("这是一条测试日志");
}
}优缺点
优点
- 符合开闭原则:新增产品时,只需要添加对应的具体产品类和具体工厂类,不需要修改现有代码
- 解耦:客户端代码与具体产品的实现解耦,只依赖于抽象接口
- 灵活:可以根据不同条件创建不同类型的对象
- 便于扩展:系统更容易扩展,新增产品不会影响现有功能
缺点
- 增加了类的数量:每增加一个产品,就需要增加一个具体产品类和一个具体工厂类
- 增加了系统的复杂度:引入了抽象层,可能增加理解难度
与简单工厂模式的区别
工厂方法模式与简单工厂模式的主要区别在于:
- 职责单一:工厂方法模式将对象创建的职责分散到不同的工厂子类中,每个工厂只负责创建一种产品
- 开闭原则:工厂方法模式符合开闭原则,而简单工厂模式在新增产品时需要修改工厂类
- 扩展性:工厂方法模式更易于扩展,可以通过继承来创建新的产品类型
简单工厂模式适用于产品种类较少且变化不大的场景,而工厂方法模式适用于产品种类较多或变化较大的场景。
总结
工厂方法模式是一种灵活、可扩展的创建型设计模式,它通过将对象的创建与使用分离,提供了一种更灵活的方式来创建对象。工厂方法模式符合开闭原则,便于系统扩展,特别适合那些需要根据不同条件创建不同类型对象的场景。在实际应用中,工厂方法模式常被用于创建复杂对象、配置管理、依赖注入等场景。