工厂方法模式
大约 6 分钟
工厂方法模式
什么是工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。
工厂方法模式的核心思想是:
- 定义一个用于创建对象的接口
- 让子类决定实例化哪一个类
- 工厂方法使一个类的实例化延迟到其子类
为什么需要工厂方法模式
在面向对象编程中,我们经常需要创建对象。如果直接在代码中使用new关键字创建具体类的实例,会导致代码耦合度高,难以扩展和维护。工厂方法模式通过将对象的创建过程封装起来,使得客户端代码与具体类的实现解耦。
工厂方法模式的结构
工厂方法模式包含以下几个角色:
- 抽象产品(Product):定义产品的接口
- 具体产品(ConcreteProduct):实现抽象产品接口的具体产品类
- 抽象工厂(Creator):声明工厂方法,返回一个产品对象
- 具体工厂(ConcreteCreator):实现工厂方法,返回一个具体产品实例
工厂方法模式的实现
基本实现
// 抽象产品
interface Product {
void use();
}
// 具体产品A
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 抽象工厂
abstract class Creator {
// 工厂方法
public abstract Product factoryMethod();
// 业务方法
public void someOperation() {
Product product = factoryMethod();
product.use();
}
}
// 具体工厂A
class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具体工厂B
class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
实际应用示例
// 抽象日志记录器接口
interface Logger {
void log(String message);
}
// 控制台日志记录器
class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("控制台日志: " + message);
}
}
// 文件日志记录器
class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("文件日志: " + message);
}
}
// 数据库日志记录器
class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("数据库日志: " + message);
}
}
// 抽象日志工厂
abstract class LoggerFactory {
// 工厂方法
public abstract Logger createLogger();
// 通用的日志记录方法
public void logMessage(String message) {
Logger logger = createLogger();
logger.log(message);
}
}
// 控制台日志工厂
class ConsoleLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
// 文件日志工厂
class FileLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 数据库日志工厂
class DatabaseLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
// 使用示例
public class FactoryMethodDemo {
public static void main(String[] args) {
// 使用控制台日志
LoggerFactory consoleFactory = new ConsoleLoggerFactory();
consoleFactory.logMessage("这是一条控制台日志");
// 使用文件日志
LoggerFactory fileFactory = new FileLoggerFactory();
fileFactory.logMessage("这是一条文件日志");
// 使用数据库日志
LoggerFactory databaseFactory = new DatabaseLoggerFactory();
databaseFactory.logMessage("这是一条数据库日志");
}
}
工厂方法模式的应用场景
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方
- 数据库连接:不同的数据库提供不同的连接对象,但它们都实现了相同的接口
- 文件读取器:可以读取不同类型的文件(PDF、Word、Excel等)
- 按钮渲染:不同操作系统的按钮外观不同,但功能相同
- 支付方式:支持多种支付方式(微信、支付宝、银行卡等)
工厂方法模式的优缺点
优点
- 符合开闭原则:新增产品时,只需新增具体产品类和对应的具体工厂类,无需修改原有代码
- 符合单一职责原则:每个工厂类只负责创建对应的产品
- 良好的封装性:客户端不需要知道所创建具体产品的类名,只需知道对应的工厂即可
- 扩展性好:增加新产品时,只需增加相应的具体产品类和具体工厂类
缺点
- 类数量增加:每增加一个产品,就需要增加一个具体产品类和一个具体工厂类
- 增加了系统的抽象性和复杂度:需要引入抽象层,增加了系统的抽象性和理解难度
工厂方法模式与其他创建型模式的比较
与简单工厂模式的区别
- 简单工厂模式:工厂类是具体的,只有一个工厂类负责创建所有产品
- 工厂方法模式:工厂类是抽象的,每个产品都有对应的工厂类
与抽象工厂模式的区别
- 工厂方法模式:针对单一产品等级结构
- 抽象工厂模式:针对多个产品等级结构
工厂方法模式的变体
1. 参数化工厂方法
abstract class ParametricCreator {
public Product factoryMethod(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
2. 模板方法与工厂方法结合
abstract class TemplateCreator {
// 模板方法
public void someOperation() {
Product product = factoryMethod();
// 一些公共操作
product.use();
// 一些后续操作
afterUse();
}
// 工厂方法
public abstract Product factoryMethod();
// 钩子方法
protected void afterUse() {
// 默认实现
}
}
实际项目中的应用
// 数据库连接工厂示例
interface DatabaseConnection {
void connect();
void executeQuery(String sql);
}
class MySQLConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("连接MySQL数据库");
}
@Override
public void executeQuery(String sql) {
System.out.println("在MySQL中执行查询: " + sql);
}
}
class PostgreSQLConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("连接PostgreSQL数据库");
}
@Override
public void executeQuery(String sql) {
System.out.println("在PostgreSQL中执行查询: " + sql);
}
}
abstract class DatabaseConnectionFactory {
public abstract DatabaseConnection createConnection();
public void performQuery(String sql) {
DatabaseConnection connection = createConnection();
connection.connect();
connection.executeQuery(sql);
}
}
class MySQLConnectionFactory extends DatabaseConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new MySQLConnection();
}
}
class PostgreSQLConnectionFactory extends DatabaseConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new PostgreSQLConnection();
}
}
// 使用示例
public class DatabaseDemo {
public static void main(String[] args) {
DatabaseConnectionFactory mysqlFactory = new MySQLConnectionFactory();
mysqlFactory.performQuery("SELECT * FROM users");
DatabaseConnectionFactory postgresFactory = new PostgreSQLConnectionFactory();
postgresFactory.performQuery("SELECT * FROM users");
}
}
总结
工厂方法模式是一种非常实用的创建型设计模式,它通过将对象的创建过程封装在工厂类中,实现了客户端代码与具体产品类的解耦。在实际开发中,当我们需要创建的对象具有共同的接口但有不同的实现时,工厂方法模式是一个很好的选择。
使用工厂方法模式的关键点:
- 识别出需要创建的对象具有共同的接口或父类
- 将对象的创建过程封装在专门的工厂类中
- 通过继承实现不同的具体工厂来创建不同的具体产品
- 客户端通过抽象工厂接口来使用具体工厂,而不需要关心具体产品的创建细节
工厂方法模式虽然会增加类的数量,但它提供了良好的扩展性和维护性,是面向对象设计中非常重要的模式之一。