工厂模式详解

1 阅读19分钟

深入理解设计模式之工厂方法模式(Factory Method Pattern)

一、引言

在软件开发中,对象创建是一个非常常见的操作。但是,如果在代码中直接使用new操作符创建对象,会导致代码与具体类紧密耦合,降低系统的灵活性和可扩展性。工厂方法模式正是为了解决这个问题而诞生的一种创建型设计模式。

本文将深入探讨工厂方法模式的原理、实现方式,并结合实际生产场景和开源框架(如JDK、Spring、Guava)中的应用,帮助你全面掌握这一重要的设计模式。

二、什么是工厂方法模式

2.1 定义

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。

2.2 核心思想

  • 封装对象创建:将对象的创建逻辑封装在工厂方法中
  • 依赖抽象而非具体:客户端依赖抽象产品和抽象工厂
  • 开闭原则:添加新产品时无需修改现有代码
  • 单一职责:将产品创建职责分离到专门的工厂类

2.3 模式结构

┌──────────────────────┐
│    <<interface>>     │
│      Product         │    抽象产品
├──────────────────────┤
│ + operation()        │
└──────────────────────┘
           △
           │ 实现
     ┌─────┴──────┐
     │            │
┌────┴─────┐  ┌──┴────────┐
│ConcreteA │  │ConcreteB  │  具体产品
└──────────┘  └───────────┘
     △              △
     │创建          │创建
     │              │
┌────┴─────────────┴────┐
│   <<abstract>>         │
│      Creator           │    抽象创建者
├────────────────────────┤
│ + factoryMethod()      │ <-- 工厂方法(抽象)
│ + operation()          │ <-- 使用产品的业务方法
└────────────────────────┘
           △
           │ 继承
     ┌─────┴──────┐
     │            │
┌────┴────────┐  ┌┴────────────┐
│CreatorA     │  │CreatorB     │  具体创建者
├─────────────┤  ├─────────────┤
│factoryMethod│  │factoryMethod│ <-- 返回具体产品
└─────────────┘  └─────────────┘

调用流程:
Client → Creator.operation() → factoryMethod() → ConcreteProduct

2.4 与简单工厂的区别

简单工厂(不是GoF23种模式之一):
┌─────────────┐      ┌──────────────┐
│   Client    │─────→│SimpleFactory │
└─────────────┘      ├──────────────┤
                     │+ create(type)│
                     └───────┬──────┘
                             │创建
                    ┌────────┼────────┐
                    ▼        ▼        ▼
               ProductA  ProductB  ProductC

工厂方法:
┌─────────────┐      ┌──────────────┐
│   Client    │─────→│   Factory    │
└─────────────┘      ├──────────────┤
                     │+ create()    │抽象方法
                     └───────△──────┘
                             │
                    ┌────────┼────────┐
                    │        │        │
                FactoryA FactoryB FactoryC
                    │        │        │
                创建│    创建│    创建│
                    ▼        ▼        ▼
               ProductA  ProductB  ProductC

三、基础示例

3.1 场景:日志记录器工厂

不同的应用场景需要不同类型的日志记录器(文件日志、数据库日志、远程日志等)。

抽象产品 - 日志记录器:

/**
 * 抽象产品:日志记录器接口
 */
public interface Logger {
    /**
     * 记录日志
     * @param message 日志消息
     */
    void log(String message);

    /**
     * 获取日志类型
     */
    String getLoggerType();
}

具体产品:

/**
 * 具体产品:文件日志记录器
 */
public class FileLogger implements Logger {

    private String filePath;

    public FileLogger(String filePath) {
        this.filePath = filePath;
    }

    @Override
    public void log(String message) {
        System.out.println("[FileLogger] 写入文件 " + filePath + ": " + message);
        // 实际实现中会写入文件
    }

    @Override
    public String getLoggerType() {
        return "FILE";
    }
}

/**
 * 具体产品:数据库日志记录器
 */
public class DatabaseLogger implements Logger {

    private String connectionString;

    public DatabaseLogger(String connectionString) {
        this.connectionString = connectionString;
    }

    @Override
    public void log(String message) {
        System.out.println("[DatabaseLogger] 写入数据库 " + connectionString + ": " + message);
        // 实际实现中会写入数据库
    }

    @Override
    public String getLoggerType() {
        return "DATABASE";
    }
}

/**
 * 具体产品:控制台日志记录器
 */
public class ConsoleLogger implements Logger {

    @Override
    public void log(String message) {
        System.out.println("[ConsoleLogger] " + message);
    }

    @Override
    public String getLoggerType() {
        return "CONSOLE";
    }
}

抽象工厂:

/**
 * 抽象创建者:日志工厂
 */
public abstract class LoggerFactory {

    /**
     * 工厂方法:创建日志记录器(由子类实现)
     */
    protected abstract Logger createLogger();

    /**
     * 业务方法:记录日志
     * 这个方法使用工厂方法创建的产品
     */
    public void writeLog(String message) {
        // 使用工厂方法获取日志记录器
        Logger logger = createLogger();

        // 添加时间戳
        String timestamp = java.time.LocalDateTime.now().toString();
        String formattedMessage = "[" + timestamp + "] " + message;

        // 记录日志
        logger.log(formattedMessage);

        // 可以添加更多通用逻辑
        System.out.println("日志已通过 " + logger.getLoggerType() + " 记录");
    }
}

具体工厂:

/**
 * 具体创建者:文件日志工厂
 */
public class FileLoggerFactory extends LoggerFactory {

    private String filePath;

    public FileLoggerFactory(String filePath) {
        this.filePath = filePath;
    }

    @Override
    protected Logger createLogger() {
        return new FileLogger(filePath);
    }
}

/**
 * 具体创建者:数据库日志工厂
 */
public class DatabaseLoggerFactory extends LoggerFactory {

    private String connectionString;

    public DatabaseLoggerFactory(String connectionString) {
        this.connectionString = connectionString;
    }

    @Override
    protected Logger createLogger() {
        return new DatabaseLogger(connectionString);
    }
}

/**
 * 具体创建者:控制台日志工厂
 */
public class ConsoleLoggerFactory extends LoggerFactory {

    @Override
    protected Logger createLogger() {
        return new ConsoleLogger();
    }
}

客户端使用:

public class LoggerTest {
    public static void main(String[] args) {
        // 根据配置选择不同的工厂
        String logType = getLogTypeFromConfig(); // 可以从配置文件读取

        LoggerFactory factory;

        switch (logType) {
            case "file":
                factory = new FileLoggerFactory("/var/log/app.log");
                break;
            case "database":
                factory = new DatabaseLoggerFactory("jdbc:mysql://localhost/logs");
                break;
            default:
                factory = new ConsoleLoggerFactory();
        }

        // 客户端代码不需要知道具体的日志记录器类型
        factory.writeLog("应用程序启动");
        factory.writeLog("用户登录成功");
    }

    private static String getLogTypeFromConfig() {
        // 模拟从配置读取
        return "file";
    }
}

输出:

[FileLogger] 写入文件 /var/log/app.log: [2025-01-19T10:30:00] 应用程序启动
日志已通过 FILE 记录
[FileLogger] 写入文件 /var/log/app.log: [2025-01-19T10:30:01] 用户登录成功
日志已通过 FILE 记录

四、实际生产场景应用

4.1 场景:数据库连接工厂

在企业应用中,需要支持多种数据库(MySQL、PostgreSQL、Oracle等),每种数据库的连接方式不同。

/**
 * 抽象产品:数据库连接
 */
public interface DatabaseConnection {
    /**
     * 连接数据库
     */
    void connect();

    /**
     * 执行SQL
     */
    void executeQuery(String sql);

    /**
     * 断开连接
     */
    void disconnect();

    /**
     * 获取数据库类型
     */
    String getDatabaseType();
}

/**
 * 具体产品:MySQL连接
 */
public class MySqlConnection implements DatabaseConnection {

    private String host;
    private int port;
    private String database;
    private boolean connected = false;

    public MySqlConnection(String host, int port, String database) {
        this.host = host;
        this.port = port;
        this.database = database;
    }

    @Override
    public void connect() {
        System.out.println("连接到 MySQL: " + host + ":" + port + "/" + database);
        // 实际实现:使用JDBC连接MySQL
        // Connection conn = DriverManager.getConnection(url, user, password);
        connected = true;
    }

    @Override
    public void executeQuery(String sql) {
        if (!connected) {
            throw new IllegalStateException("未连接到数据库");
        }
        System.out.println("[MySQL] 执行SQL: " + sql);
        // 实际实现:执行SQL查询
    }

    @Override
    public void disconnect() {
        System.out.println("断开 MySQL 连接");
        connected = false;
    }

    @Override
    public String getDatabaseType() {
        return "MySQL";
    }
}

/**
 * 具体产品:PostgreSQL连接
 */
public class PostgreSqlConnection implements DatabaseConnection {

    private String host;
    private int port;
    private String database;
    private boolean connected = false;

    public PostgreSqlConnection(String host, int port, String database) {
        this.host = host;
        this.port = port;
        this.database = database;
    }

    @Override
    public void connect() {
        System.out.println("连接到 PostgreSQL: " + host + ":" + port + "/" + database);
        connected = true;
    }

    @Override
    public void executeQuery(String sql) {
        if (!connected) {
            throw new IllegalStateException("未连接到数据库");
        }
        System.out.println("[PostgreSQL] 执行SQL: " + sql);
    }

    @Override
    public void disconnect() {
        System.out.println("断开 PostgreSQL 连接");
        connected = false;
    }

    @Override
    public String getDatabaseType() {
        return "PostgreSQL";
    }
}

/**
 * 具体产品:Oracle连接
 */
public class OracleConnection implements DatabaseConnection {

    private String host;
    private int port;
    private String sid;
    private boolean connected = false;

    public OracleConnection(String host, int port, String sid) {
        this.host = host;
        this.port = port;
        this.sid = sid;
    }

    @Override
    public void connect() {
        System.out.println("连接到 Oracle: " + host + ":" + port + " SID=" + sid);
        connected = true;
    }

    @Override
    public void executeQuery(String sql) {
        if (!connected) {
            throw new IllegalStateException("未连接到数据库");
        }
        System.out.println("[Oracle] 执行SQL: " + sql);
    }

    @Override
    public void disconnect() {
        System.out.println("断开 Oracle 连接");
        connected = false;
    }

    @Override
    public String getDatabaseType() {
        return "Oracle";
    }
}

抽象工厂和具体工厂:

/**
 * 抽象创建者:数据库连接工厂
 */
public abstract class DatabaseConnectionFactory {

    /**
     * 工厂方法:创建数据库连接
     */
    protected abstract DatabaseConnection createConnection();

    /**
     * 模板方法:执行数据库操作
     */
    public void executeOperation(String sql) {
        DatabaseConnection connection = null;

        try {
            // 1. 创建连接
            connection = createConnection();

            // 2. 连接数据库
            connection.connect();

            // 3. 执行SQL
            connection.executeQuery(sql);

        } catch (Exception e) {
            System.err.println("数据库操作失败: " + e.getMessage());
        } finally {
            // 4. 关闭连接
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    /**
     * 获取连接池(高级功能)
     */
    public DatabaseConnection getConnection() {
        return createConnection();
    }
}

/**
 * 具体创建者:MySQL连接工厂
 */
public class MySqlConnectionFactory extends DatabaseConnectionFactory {

    private String host;
    private int port;
    private String database;

    public MySqlConnectionFactory(String host, int port, String database) {
        this.host = host;
        this.port = port;
        this.database = database;
    }

    @Override
    protected DatabaseConnection createConnection() {
        return new MySqlConnection(host, port, database);
    }
}

/**
 * 具体创建者:PostgreSQL连接工厂
 */
public class PostgreSqlConnectionFactory extends DatabaseConnectionFactory {

    private String host;
    private int port;
    private String database;

    public PostgreSqlConnectionFactory(String host, int port, String database) {
        this.host = host;
        this.port = port;
        this.database = database;
    }

    @Override
    protected DatabaseConnection createConnection() {
        return new PostgreSqlConnection(host, port, database);
    }
}

/**
 * 具体创建者:Oracle连接工厂
 */
public class OracleConnectionFactory extends DatabaseConnectionFactory {

    private String host;
    private int port;
    private String sid;

    public OracleConnectionFactory(String host, int port, String sid) {
        this.host = host;
        this.port = port;
        this.sid = sid;
    }

    @Override
    protected DatabaseConnection createConnection() {
        return new OracleConnection(host, port, sid);
    }
}

客户端使用:

public class DatabaseTest {
    public static void main(String[] args) {
        // 从配置文件读取数据库类型
        String dbType = System.getProperty("db.type", "mysql");

        // 根据配置创建对应的工厂
        DatabaseConnectionFactory factory = createFactory(dbType);

        // 执行数据库操作(客户端不需要知道具体数据库类型)
        factory.executeOperation("SELECT * FROM users WHERE id = 1");
        factory.executeOperation("INSERT INTO logs VALUES (1, 'test')");
    }

    private static DatabaseConnectionFactory createFactory(String dbType) {
        switch (dbType.toLowerCase()) {
            case "mysql":
                return new MySqlConnectionFactory("localhost", 3306, "mydb");
            case "postgresql":
                return new PostgreSqlConnectionFactory("localhost", 5432, "mydb");
            case "oracle":
                return new OracleConnectionFactory("localhost", 1521, "ORCL");
            default:
                throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
        }
    }
}

4.2 场景:消息推送工厂

在现代应用中,需要支持多种消息推送渠道(邮件、短信、微信、App推送等)。

/**
 * 抽象产品:消息推送器
 */
public interface MessagePusher {
    /**
     * 发送消息
     */
    boolean send(String recipient, String title, String content);

    /**
     * 批量发送
     */
    int batchSend(java.util.List<String> recipients, String title, String content);

    /**
     * 获取推送类型
     */
    String getPusherType();
}

/**
 * 具体产品:邮件推送
 */
public class EmailPusher implements MessagePusher {

    private String smtpServer;
    private String username;

    public EmailPusher(String smtpServer, String username) {
        this.smtpServer = smtpServer;
        this.username = username;
    }

    @Override
    public boolean send(String recipient, String title, String content) {
        System.out.println("=== 发送邮件 ===");
        System.out.println("SMTP服务器: " + smtpServer);
        System.out.println("发件人: " + username);
        System.out.println("收件人: " + recipient);
        System.out.println("主题: " + title);
        System.out.println("内容: " + content);
        // 实际实现:使用JavaMail API发送邮件
        return true;
    }

    @Override
    public int batchSend(java.util.List<String> recipients, String title, String content) {
        int successCount = 0;
        for (String recipient : recipients) {
            if (send(recipient, title, content)) {
                successCount++;
            }
        }
        return successCount;
    }

    @Override
    public String getPusherType() {
        return "EMAIL";
    }
}

/**
 * 具体产品:短信推送
 */
public class SmsPusher implements MessagePusher {

    private String apiKey;
    private String gateway;

    public SmsPusher(String apiKey, String gateway) {
        this.apiKey = apiKey;
        this.gateway = gateway;
    }

    @Override
    public boolean send(String recipient, String title, String content) {
        System.out.println("=== 发送短信 ===");
        System.out.println("网关: " + gateway);
        System.out.println("收件人: " + recipient);
        System.out.println("内容: " + content);
        // 实际实现:调用短信网关API
        return true;
    }

    @Override
    public int batchSend(java.util.List<String> recipients, String title, String content) {
        System.out.println("批量发送短信到 " + recipients.size() + " 个号码");
        // 实际实现:调用批量短信API
        return recipients.size();
    }

    @Override
    public String getPusherType() {
        return "SMS";
    }
}

/**
 * 具体产品:微信推送
 */
public class WeChatPusher implements MessagePusher {

    private String appId;
    private String appSecret;

    public WeChatPusher(String appId, String appSecret) {
        this.appId = appId;
        this.appSecret = appSecret;
    }

    @Override
    public boolean send(String recipient, String title, String content) {
        System.out.println("=== 发送微信消息 ===");
        System.out.println("AppID: " + appId);
        System.out.println("OpenID: " + recipient);
        System.out.println("标题: " + title);
        System.out.println("内容: " + content);
        // 实际实现:调用微信模板消息API
        return true;
    }

    @Override
    public int batchSend(java.util.List<String> recipients, String title, String content) {
        System.out.println("批量发送微信消息到 " + recipients.size() + " 个用户");
        return recipients.size();
    }

    @Override
    public String getPusherType() {
        return "WECHAT";
    }
}

/**
 * 抽象工厂:消息推送工厂
 */
public abstract class MessagePusherFactory {

    /**
     * 工厂方法
     */
    protected abstract MessagePusher createPusher();

    /**
     * 发送通知(带重试机制)
     */
    public boolean sendNotification(String recipient, String title, String content) {
        MessagePusher pusher = createPusher();

        // 添加重试逻辑
        int maxRetries = 3;
        for (int i = 0; i < maxRetries; i++) {
            try {
                boolean success = pusher.send(recipient, title, content);
                if (success) {
                    logSuccess(pusher, recipient);
                    return true;
                }
            } catch (Exception e) {
                System.err.println("发送失败,第 " + (i + 1) + " 次重试");
            }
        }

        logFailure(pusher, recipient);
        return false;
    }

    private void logSuccess(MessagePusher pusher, String recipient) {
        System.out.println("[SUCCESS] " + pusher.getPusherType() + " 消息发送成功: " + recipient);
    }

    private void logFailure(MessagePusher pusher, String recipient) {
        System.err.println("[FAILURE] " + pusher.getPusherType() + " 消息发送失败: " + recipient);
    }
}

/**
 * 具体工厂实现
 */
public class EmailPusherFactory extends MessagePusherFactory {
    @Override
    protected MessagePusher createPusher() {
        return new EmailPusher("smtp.example.com", "noreply@example.com");
    }
}

public class SmsPusherFactory extends MessagePusherFactory {
    @Override
    protected MessagePusher createPusher() {
        return new SmsPusher("your-api-key", "https://sms.gateway.com");
    }
}

public class WeChatPusherFactory extends MessagePusherFactory {
    @Override
    protected MessagePusher createPusher() {
        return new WeChatPusher("wx1234567890", "your-app-secret");
    }
}

五、开源框架中的应用

5.1 JDK中的应用

Collection接口的iterator()方法:

import java.util.*;

/**
 * JDK中最典型的工厂方法模式应用
 * Collection接口定义了iterator()工厂方法
 */
public class JdkIteratorExample {

    public static void main(String[] args) {
        // ArrayList实现了iterator()工厂方法
        Collection<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("Go");

        // iterator()是工厂方法,返回Iterator对象
        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // HashSet也实现了iterator()工厂方法,返回不同的迭代器实现
        Collection<String> set = new HashSet<>();
        set.add("A");
        set.add("B");

        Iterator<String> setIterator = set.iterator();
        // 使用方式相同,但内部实现不同
    }
}

/**
 * 简化的Collection接口结构
 */
interface SimpleCollection<E> {
    /**
     * 工厂方法:由具体集合类实现
     */
    Iterator<E> iterator();

    boolean add(E e);
    int size();
}

/**
 * 具体实现:ArrayList
 */
class SimpleArrayList<E> implements SimpleCollection<E> {
    private Object[] elements = new Object[10];
    private int size = 0;

    @Override
    public Iterator<E> iterator() {
        // 返回ArrayList特定的迭代器
        return new ArrayListIterator();
    }

    @Override
    public boolean add(E e) {
        elements[size++] = e;
        return true;
    }

    @Override
    public int size() {
        return size;
    }

    /**
     * ArrayList的迭代器实现
     */
    private class ArrayListIterator implements Iterator<E> {
        private int cursor = 0;

        @Override
        public boolean hasNext() {
            return cursor < size;
        }

        @Override
        @SuppressWarnings("unchecked")
        public E next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            return (E) elements[cursor++];
        }
    }
}

/**
 * 具体实现:LinkedList
 */
class SimpleLinkedList<E> implements SimpleCollection<E> {
    private Node<E> first;
    private int size = 0;

    @Override
    public Iterator<E> iterator() {
        // 返回LinkedList特定的迭代器
        return new LinkedListIterator();
    }

    @Override
    public boolean add(E e) {
        Node<E> newNode = new Node<>(e);
        if (first == null) {
            first = newNode;
        } else {
            Node<E> current = first;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
        size++;
        return true;
    }

    @Override
    public int size() {
        return size;
    }

    /**
     * LinkedList的迭代器实现
     */
    private class LinkedListIterator implements Iterator<E> {
        private Node<E> current = first;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public E next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            E data = current.data;
            current = current.next;
            return data;
        }
    }

    private static class Node<E> {
        E data;
        Node<E> next;

        Node(E data) {
            this.data = data;
        }
    }
}

5.2 JDBC中的DriverManager

import java.sql.*;

/**
 * JDBC的DriverManager是工厂方法模式的经典应用
 * getConnection()方法根据URL选择合适的Driver创建Connection
 */
public class JdbcFactoryExample {

    public static void demonstrateJdbcFactory() throws SQLException {
        // DriverManager.getConnection()是静态工厂方法
        // 根据URL前缀选择对应的Driver

        // MySQL Driver
        Connection mysqlConn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/mydb",
            "user",
            "password"
        );

        // PostgreSQL Driver
        Connection pgConn = DriverManager.getConnection(
            "jdbc:postgresql://localhost:5432/mydb",
            "user",
            "password"
        );

        // 客户端代码使用相同的Connection接口
        Statement stmt = mysqlConn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM users");
    }
}

/**
 * 简化的JDBC工厂方法模式实现
 */
interface Driver {
    Connection connect(String url, java.util.Properties info) throws SQLException;
    boolean acceptsURL(String url) throws SQLException;
}

class DriverManager {
    private static java.util.List<Driver> registeredDrivers = new java.util.ArrayList<>();

    /**
     * 工厂方法:根据URL创建合适的Connection
     */
    public static Connection getConnection(String url, String user, String password)
            throws SQLException {

        // 遍历注册的Driver,找到能处理该URL的Driver
        for (Driver driver : registeredDrivers) {
            if (driver.acceptsURL(url)) {
                java.util.Properties info = new java.util.Properties();
                info.put("user", user);
                info.put("password", password);

                // 使用找到的Driver创建Connection
                Connection conn = driver.connect(url, info);
                if (conn != null) {
                    return conn;
                }
            }
        }

        throw new SQLException("No suitable driver found for " + url);
    }

    public static void registerDriver(Driver driver) {
        registeredDrivers.add(driver);
    }
}

5.3 Spring Framework中的FactoryBean

import org.springframework.beans.factory.FactoryBean;

/**
 * Spring的FactoryBean是工厂方法模式的应用
 * 用于创建复杂对象或需要特殊初始化的对象
 */
public class ConnectionPoolFactoryBean implements FactoryBean<ConnectionPool> {

    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private int maxConnections = 10;

    /**
     * 工厂方法:创建ConnectionPool对象
     */
    @Override
    public ConnectionPool getObject() throws Exception {
        ConnectionPool pool = new ConnectionPool();
        pool.setDriverClassName(driverClassName);
        pool.setUrl(url);
        pool.setUsername(username);
        pool.setPassword(password);
        pool.setMaxConnections(maxConnections);

        // 初始化连接池
        pool.initialize();

        return pool;
    }

    @Override
    public Class<?> getObjectType() {
        return ConnectionPool.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    // Setters for dependency injection
    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }
}

/**
 * 连接池类
 */
class ConnectionPool {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private int maxConnections;

    public void initialize() {
        System.out.println("初始化连接池: " + url);
        // 创建初始连接
    }

    // Getters and Setters
    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }
}

/**
 * Spring配置文件使用示例:
 *
 * <bean id="connectionPool" class="com.example.ConnectionPoolFactoryBean">
 *     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
 *     <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
 *     <property name="username" value="root"/>
 *     <property name="password" value="password"/>
 *     <property name="maxConnections" value="20"/>
 * </bean>
 *
 * 当获取connectionPool bean时,实际得到的是FactoryBean.getObject()返回的对象
 */

5.4 Guava中的LoadingCache

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

/**
 * Guava的CacheBuilder使用工厂方法模式
 * CacheLoader.load()是工厂方法,用于创建缓存值
 */
public class GuavaCacheFactoryExample {

    public static void main(String[] args) throws Exception {
        // CacheLoader定义了如何创建缓存值
        LoadingCache<String, User> userCache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .build(new CacheLoader<String, User>() {
                @Override
                public User load(String userId) throws Exception {
                    // 工厂方法:当缓存中没有该key时,调用此方法创建对象
                    return loadUserFromDatabase(userId);
                }
            });

        // 使用缓存
        User user1 = userCache.get("user123"); // 第一次访问,调用load()
        User user2 = userCache.get("user123"); // 第二次访问,直接从缓存获取

        System.out.println("两次获取的是同一个对象: " + (user1 == user2));
    }

    private static User loadUserFromDatabase(String userId) {
        System.out.println("从数据库加载用户: " + userId);
        User user = new User();
        user.setName("User-" + userId);
        user.setEmail(userId + "@example.com");
        return user;
    }
}

/**
 * 自定义实现类似的缓存工厂
 */
abstract class DataLoader<K, V> {
    private java.util.Map<K, V> cache = new java.util.HashMap<>();

    /**
     * 工厂方法:由子类实现具体的加载逻辑
     */
    protected abstract V load(K key) throws Exception;

    /**
     * 获取数据(带缓存)
     */
    public V get(K key) throws Exception {
        if (cache.containsKey(key)) {
            return cache.get(key);
        }

        // 调用工厂方法创建对象
        V value = load(key);
        cache.put(key, value);
        return value;
    }
}

/**
 * 具体实现:用户数据加载器
 */
class UserDataLoader extends DataLoader<String, User> {
    @Override
    protected User load(String userId) throws Exception {
        System.out.println("从数据源加载用户: " + userId);
        // 实际实现:从数据库、API等加载数据
        User user = new User();
        user.setName("User-" + userId);
        return user;
    }
}

六、工厂方法模式的优缺点

6.1 优点

1. 符合开闭原则

添加新产品时的变化:

不使用工厂方法:
❌ 修改客户端代码中的switch/if语句
❌ 直接在代码中new具体类

使用工厂方法:
✓ 创建新的产品类
✓ 创建新的工厂类
✓ 客户端代码无需修改

2. 符合单一职责原则

  • 产品创建逻辑集中在工厂类中
  • 客户端只关注产品的使用,不关心创建细节

3. 符合依赖倒置原则

依赖关系:

Client → AbstractFactory → AbstractProduct
              ↑                  ↑
              │                  │
      ConcreteFactory    ConcreteProduct

客户端依赖抽象,不依赖具体实现

4. 提高代码复用性

  • 通用的创建逻辑可以在抽象工厂中实现
  • 子类只需实现特定的创建细节

6.2 缺点

1. 类的数量增加

每增加一个产品:
- 1个具体产品类
- 1个具体工厂类

产品种类多时,类的数量会快速增长

2. 增加系统复杂度

  • 引入了额外的抽象层
  • 需要理解工厂和产品的关系

3. 增加理解难度

  • 对象创建逻辑分散在多个类中
  • 新手可能难以快速定位代码

七、最佳实践

7.1 使用配置文件驱动工厂选择

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 使用配置文件选择工厂
 */
public class ConfigDrivenFactory {

    private static Properties config = new Properties();

    static {
        try (InputStream is = ConfigDrivenFactory.class
                .getResourceAsStream("/factory.properties")) {
            config.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据配置创建工厂
     */
    public static LoggerFactory createLoggerFactory() {
        String logType = config.getProperty("logger.type", "console");

        switch (logType) {
            case "file":
                String filePath = config.getProperty("logger.file.path", "/tmp/app.log");
                return new FileLoggerFactory(filePath);
            case "database":
                String connStr = config.getProperty("logger.db.connection");
                return new DatabaseLoggerFactory(connStr);
            default:
                return new ConsoleLoggerFactory();
        }
    }
}

/**
 * factory.properties配置文件内容:
 *
 * logger.type=file
 * logger.file.path=/var/log/application.log
 *
 * # 或者
 * logger.type=database
 * logger.db.connection=jdbc:mysql://localhost/logs
 */

7.2 结合反射实现通用工厂

/**
 * 使用反射的通用工厂
 */
public class ReflectionFactory<T> {

    private Class<? extends T> productClass;

    public ReflectionFactory(Class<? extends T> productClass) {
        this.productClass = productClass;
    }

    /**
     * 工厂方法:使用反射创建对象
     */
    public T createProduct() {
        try {
            return productClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("无法创建对象: " + productClass.getName(), e);
        }
    }

    /**
     * 带参数的工厂方法
     */
    public T createProduct(Object... args) {
        try {
            // 获取参数类型
            Class<?>[] paramTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                paramTypes[i] = args[i].getClass();
            }

            // 获取构造函数并创建对象
            return productClass.getDeclaredConstructor(paramTypes).newInstance(args);
        } catch (Exception e) {
            throw new RuntimeException("无法创建对象: " + productClass.getName(), e);
        }
    }
}

/**
 * 使用示例
 */
class ReflectionFactoryTest {
    public static void main(String[] args) {
        // 创建ConsoleLogger
        ReflectionFactory<Logger> factory1 =
            new ReflectionFactory<>(ConsoleLogger.class);
        Logger logger1 = factory1.createProduct();
        logger1.log("测试消息");

        // 创建FileLogger(带参数)
        ReflectionFactory<Logger> factory2 =
            new ReflectionFactory<>(FileLogger.class);
        Logger logger2 = factory2.createProduct("/tmp/test.log");
        logger2.log("测试消息");
    }
}

7.3 使用注解标记工厂

import java.lang.annotation.*;

/**
 * 工厂注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FactoryProduct {
    String type();
}

/**
 * 使用注解标记产品类型
 */
@FactoryProduct(type = "console")
class ConsoleLoggerV2 implements Logger {
    @Override
    public void log(String message) {
        System.out.println(message);
    }

    @Override
    public String getLoggerType() {
        return "CONSOLE";
    }
}

@FactoryProduct(type = "file")
class FileLoggerV2 implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[File] " + message);
    }

    @Override
    public String getLoggerType() {
        return "FILE";
    }
}

/**
 * 基于注解的工厂
 */
class AnnotationBasedFactory {

    private static java.util.Map<String, Class<? extends Logger>> registry =
        new java.util.HashMap<>();

    /**
     * 注册所有带@FactoryProduct注解的类
     */
    public static void scanAndRegister(String packageName) {
        // 简化实现,实际需要使用classpath扫描
        registerProduct(ConsoleLoggerV2.class);
        registerProduct(FileLoggerV2.class);
    }

    private static void registerProduct(Class<? extends Logger> clazz) {
        FactoryProduct annotation = clazz.getAnnotation(FactoryProduct.class);
        if (annotation != null) {
            registry.put(annotation.type(), clazz);
        }
    }

    /**
     * 根据类型创建产品
     */
    public static Logger createLogger(String type) {
        Class<? extends Logger> clazz = registry.get(type);
        if (clazz == null) {
            throw new IllegalArgumentException("未找到类型: " + type);
        }

        try {
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建失败", e);
        }
    }
}

7.4 工厂方法+单例模式

/**
 * 工厂方法与单例模式结合
 * 确保每种类型的产品只创建一次
 */
public abstract class SingletonFactory<T> {

    private T instance;

    /**
     * 抽象工厂方法
     */
    protected abstract T createInstance();

    /**
     * 获取单例实例
     */
    public synchronized T getInstance() {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }
}

/**
 * 具体实现
 */
class DatabaseConnectionSingletonFactory extends SingletonFactory<DatabaseConnection> {

    @Override
    protected DatabaseConnection createInstance() {
        System.out.println("创建数据库连接(仅一次)");
        return new MySqlConnection("localhost", 3306, "mydb");
    }
}

/**
 * 使用示例
 */
class SingletonFactoryTest {
    public static void main(String[] args) {
        SingletonFactory<DatabaseConnection> factory =
            new DatabaseConnectionSingletonFactory();

        DatabaseConnection conn1 = factory.getInstance();
        DatabaseConnection conn2 = factory.getInstance();

        System.out.println("是同一个对象: " + (conn1 == conn2)); // true
    }
}

八、工厂方法 vs 其他创建型模式

8.1 工厂方法 vs 抽象工厂

工厂方法(Factory Method):
┌─────────────┐
│   Factory   │
├─────────────┤
│+ create()   │ ──→ 创建一个产品
└─────────────┘

抽象工厂(Abstract Factory):
┌─────────────────┐
│ AbstractFactory │
├─────────────────┤
│+ createProductA │ ──→ 创建产品A
│+ createProductB │ ──→ 创建产品B
│+ createProductC │ ──→ 创建产品C
└─────────────────┘

区别:
- 工厂方法:一个工厂创建一种产品
- 抽象工厂:一个工厂创建一系列相关产品

8.2 工厂方法 vs 建造者模式

工厂方法:
- 关注点:创建什么产品
- 复杂度:产品创建相对简单
- 使用场景:产品类型多样

建造者模式:
- 关注点:如何创建产品
- 复杂度:产品创建过程复杂
- 使用场景:产品内部结构复杂

示例对比:
// 工厂方法
Logger logger = factory.createLogger();

// 建造者
User user = new UserBuilder()
    .setName("John")
    .setAge(30)
    .setEmail("john@example.com")
    .build();

九、实战演练:构建文档转换器工厂

/**
 * 抽象产品:文档转换器
 */
public interface DocumentConverter {
    /**
     * 转换文档
     * @param sourceFile 源文件路径
     * @param targetFile 目标文件路径
     * @return 是否转换成功
     */
    boolean convert(String sourceFile, String targetFile);

    /**
     * 获取支持的源格式
     */
    String getSourceFormat();

    /**
     * 获取支持的目标格式
     */
    String getTargetFormat();
}

/**
 * 具体产品:PDF转Word
 */
public class PdfToWordConverter implements DocumentConverter {

    @Override
    public boolean convert(String sourceFile, String targetFile) {
        System.out.println("开始转换: " + sourceFile + " -> " + targetFile);
        System.out.println("使用Apache PDFBox解析PDF...");
        System.out.println("使用Apache POI生成Word文档...");
        System.out.println("转换完成!");
        return true;
    }

    @Override
    public String getSourceFormat() {
        return "PDF";
    }

    @Override
    public String getTargetFormat() {
        return "WORD";
    }
}

/**
 * 具体产品:Word转PDF
 */
public class WordToPdfConverter implements DocumentConverter {

    @Override
    public boolean convert(String sourceFile, String targetFile) {
        System.out.println("开始转换: " + sourceFile + " -> " + targetFile);
        System.out.println("使用Apache POI解析Word文档...");
        System.out.println("使用iText生成PDF...");
        System.out.println("转换完成!");
        return true;
    }

    @Override
    public String getSourceFormat() {
        return "WORD";
    }

    @Override
    public String getTargetFormat() {
        return "PDF";
    }
}

/**
 * 具体产品:Markdown转HTML
 */
public class MarkdownToHtmlConverter implements DocumentConverter {

    @Override
    public boolean convert(String sourceFile, String targetFile) {
        System.out.println("开始转换: " + sourceFile + " -> " + targetFile);
        System.out.println("使用CommonMark解析Markdown...");
        System.out.println("生成HTML文件...");
        System.out.println("转换完成!");
        return true;
    }

    @Override
    public String getSourceFormat() {
        return "MARKDOWN";
    }

    @Override
    public String getTargetFormat() {
        return "HTML";
    }
}

/**
 * 抽象工厂:文档转换器工厂
 */
public abstract class DocumentConverterFactory {

    /**
     * 工厂方法:创建转换器
     */
    protected abstract DocumentConverter createConverter();

    /**
     * 执行转换(模板方法)
     */
    public boolean performConversion(String sourceFile, String targetFile) {
        try {
            // 1. 验证文件
            validateFiles(sourceFile, targetFile);

            // 2. 创建转换器
            DocumentConverter converter = createConverter();

            // 3. 显示转换信息
            System.out.println("\n=== 文档转换任务 ===");
            System.out.println("转换类型: " + converter.getSourceFormat() +
                             " → " + converter.getTargetFormat());
            System.out.println("源文件: " + sourceFile);
            System.out.println("目标文件: " + targetFile);
            System.out.println("==================\n");

            // 4. 执行转换
            boolean success = converter.convert(sourceFile, targetFile);

            // 5. 记录日志
            if (success) {
                logSuccess(converter, sourceFile, targetFile);
            } else {
                logFailure(converter, sourceFile, targetFile);
            }

            return success;

        } catch (Exception e) {
            System.err.println("转换失败: " + e.getMessage());
            return false;
        }
    }

    private void validateFiles(String sourceFile, String targetFile) {
        if (sourceFile == null || targetFile == null) {
            throw new IllegalArgumentException("文件路径不能为空");
        }
    }

    private void logSuccess(DocumentConverter converter, String source, String target) {
        System.out.println("\n✓ 转换成功: " + converter.getSourceFormat() +
                         " → " + converter.getTargetFormat());
    }

    private void logFailure(DocumentConverter converter, String source, String target) {
        System.err.println("\n✗ 转换失败: " + converter.getSourceFormat() +
                         " → " + converter.getTargetFormat());
    }
}

/**
 * 具体工厂实现
 */
public class PdfToWordConverterFactory extends DocumentConverterFactory {
    @Override
    protected DocumentConverter createConverter() {
        return new PdfToWordConverter();
    }
}

public class WordToPdfConverterFactory extends DocumentConverterFactory {
    @Override
    protected DocumentConverter createConverter() {
        return new WordToPdfConverter();
    }
}

public class MarkdownToHtmlConverterFactory extends DocumentConverterFactory {
    @Override
    protected DocumentConverter createConverter() {
        return new MarkdownToHtmlConverter();
    }
}

/**
 * 工厂注册表(简化客户端使用)
 */
public class ConverterFactoryRegistry {

    private static java.util.Map<String, DocumentConverterFactory> factories =
        new java.util.HashMap<>();

    static {
        // 注册所有工厂
        factories.put("pdf-to-word", new PdfToWordConverterFactory());
        factories.put("word-to-pdf", new WordToPdfConverterFactory());
        factories.put("markdown-to-html", new MarkdownToHtmlConverterFactory());
    }

    /**
     * 根据转换类型获取工厂
     */
    public static DocumentConverterFactory getFactory(String conversionType) {
        DocumentConverterFactory factory = factories.get(conversionType);
        if (factory == null) {
            throw new IllegalArgumentException("不支持的转换类型: " + conversionType);
        }
        return factory;
    }

    /**
     * 列出所有支持的转换类型
     */
    public static void listSupportedConversions() {
        System.out.println("支持的转换类型:");
        factories.keySet().forEach(type -> System.out.println("  - " + type));
    }
}

/**
 * 测试类
 */
public class DocumentConverterTest {
    public static void main(String[] args) {
        // 列出支持的转换类型
        ConverterFactoryRegistry.listSupportedConversions();

        // 场景1: PDF转Word
        DocumentConverterFactory factory1 =
            ConverterFactoryRegistry.getFactory("pdf-to-word");
        factory1.performConversion("/docs/report.pdf", "/docs/report.docx");

        // 场景2: Word转PDF
        DocumentConverterFactory factory2 =
            ConverterFactoryRegistry.getFactory("word-to-pdf");
        factory2.performConversion("/docs/article.docx", "/docs/article.pdf");

        // 场景3: Markdown转HTML
        DocumentConverterFactory factory3 =
            ConverterFactoryRegistry.getFactory("markdown-to-html");
        factory3.performConversion("/docs/README.md", "/docs/README.html");
    }
}

十、总结

10.1 核心要点

  1. 工厂方法模式的本质:定义创建对象的接口,由子类决定实例化哪个类
  2. 适用场景
    • 不知道具体需要哪个类的实例
    • 希望通过子类指定创建对象
    • 将对象创建职责委托给子类
  3. 关键技巧
    • 抽象工厂定义工厂方法
    • 具体工厂实现工厂方法
    • 客户端依赖抽象,不依赖具体

10.2 使用建议

选择工厂方法模式的检查清单:

✓ 是否需要在运行时决定创建哪个类的实例?
✓ 是否有多种产品类型,且可能继续增加?
✓ 是否希望将对象创建逻辑与使用逻辑分离?
✓ 是否需要在不修改客户端代码的情况下扩展新产品?

如果以上都是"是",那么工厂方法模式是个好选择!

10.3 实践原则

  1. 合理使用:不是所有对象创建都需要工厂方法
  2. 保持简单:如果只有2-3个产品,考虑简单工厂
  3. 结合其他模式:可以与单例、原型等模式结合
  4. 文档化:清晰记录各工厂创建的产品类型