Java设计模式 二十六 工厂模式 + 单例模式

工厂模式 + 单例模式

工厂模式单例模式的组合是一种常见的设计模式组合,通常用于确保某些全局共享的资源(如配置管理器、数据库连接池等)只有一个实例,同时通过工厂方法提供统一的对象创建方式。


1. 场景说明

工厂模式用于创建对象,提供了一种灵活的对象实例化方式。单例模式用于确保某个类只有一个实例,并提供全局访问点。两者的结合通常应用于以下场景:

  • 数据库连接工厂: 确保数据库连接池只有一个工厂实例,同时提供连接对象的创建。
  • 配置管理器: 确保配置管理器类只有一个实例,通过工厂方法管理不同的配置对象。
  • 日志系统: 确保日志管理器只有一个实例,同时根据需要生成不同类型的日志记录器。

2. 模式组合的优点

  1. 唯一性: 单例模式保证工厂类的唯一性,避免了工厂类被多次实例化。
  2. 扩展性: 工厂模式为创建对象提供了灵活性,可以通过多态或其他扩展方式动态创建不同类型的对象。
  3. 全局访问: 单例模式提供了全局访问点,工厂模式集中管理对象的创建逻辑,二者结合使得系统结构清晰。

3. 实现示例:数据库连接工厂

以下示例展示了一个数据库连接工厂的实现,工厂类采用单例模式,确保只有一个工厂实例。


(1) 数据库连接类

数据库连接类表示单个连接对象。

java 复制代码
// 数据库连接类
public class DatabaseConnection {
    private String connectionString;

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

    public void connect() {
        System.out.println("连接到数据库: " + connectionString);
    }
}

(2) 工厂类

工厂类使用单例模式,确保只有一个工厂实例,负责创建数据库连接对象。

java 复制代码
// 工厂类
public class DatabaseConnectionFactory {
    // 单例实例
    private static DatabaseConnectionFactory instance;

    // 私有构造方法
    private DatabaseConnectionFactory() {}

    // 获取单例实例
    public static DatabaseConnectionFactory getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnectionFactory.class) { // 线程安全的单例
                if (instance == null) {
                    instance = new DatabaseConnectionFactory();
                }
            }
        }
        return instance;
    }

    // 工厂方法:创建数据库连接
    public DatabaseConnection createConnection(String connectionString) {
        return new DatabaseConnection(connectionString);
    }
}

(3) 客户端代码

客户端代码通过单例工厂创建数据库连接对象。

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 获取工厂实例
        DatabaseConnectionFactory factory = DatabaseConnectionFactory.getInstance();

        // 创建数据库连接
        DatabaseConnection connection1 = factory.createConnection("jdbc:mysql://localhost:3306/db1");
        connection1.connect();

        DatabaseConnection connection2 = factory.createConnection("jdbc:postgresql://localhost:5432/db2");
        connection2.connect();

        // 确保工厂是单例
        DatabaseConnectionFactory anotherFactory = DatabaseConnectionFactory.getInstance();
        System.out.println(factory == anotherFactory); // 输出: true
    }
}

运行结果:
复制代码
连接到数据库: jdbc:mysql://localhost:3306/db1
连接到数据库: jdbc:postgresql://localhost:5432/db2
true

4. 扩展示例:多类型对象的工厂

在某些场景下,工厂需要根据不同的参数创建不同类型的对象,工厂模式和单例模式的结合依然适用。例如:日志管理系统。


(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 ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("控制台日志记录: " + message);
    }
}

(3) 单例工厂类
java 复制代码
// 日志工厂类
public class LoggerFactory {
    private static LoggerFactory instance;

    private LoggerFactory() {}

    public static LoggerFactory getInstance() {
        if (instance == null) {
            synchronized (LoggerFactory.class) {
                if (instance == null) {
                    instance = new LoggerFactory();
                }
            }
        }
        return instance;
    }

    public Logger createLogger(String type) {
        if ("file".equalsIgnoreCase(type)) {
            return new FileLogger();
        } else if ("console".equalsIgnoreCase(type)) {
            return new ConsoleLogger();
        } else {
            throw new IllegalArgumentException("未知的日志类型: " + type);
        }
    }
}

(4) 客户端代码
java 复制代码
public class Client {
    public static void main(String[] args) {
        LoggerFactory loggerFactory = LoggerFactory.getInstance();

        Logger fileLogger = loggerFactory.createLogger("file");
        fileLogger.log("这是文件日志");

        Logger consoleLogger = loggerFactory.createLogger("console");
        consoleLogger.log("这是控制台日志");
    }
}

运行结果:
复制代码
文件日志记录: 这是文件日志
控制台日志记录: 这是控制台日志

5. 优缺点

优点:
  1. 全局唯一性: 单例模式确保工厂类唯一,全局共享。
  2. 灵活扩展: 工厂模式使得对象创建逻辑集中在工厂类中,新增对象类型时无需修改客户端代码。
  3. 高效管理: 工厂和单例结合能够高效管理系统中的全局资源,例如数据库连接、日志管理器等。
缺点:
  1. 复杂性增加: 模式组合会增加系统的复杂度,可能引入过度设计的问题。
  2. 线程安全性: 单例模式需要考虑多线程环境下的安全性,增加了实现的复杂性。

6. 总结

工厂模式 + 单例模式的组合是一种常见的设计模式组合,用于解决全局唯一资源的创建和管理问题。通过将工厂类设计为单例,我们可以确保全局共享的工厂实例,同时通过工厂模式灵活创建不同类型的对象。这种组合在实际开发中非常实用,特别是在需要集中管理全局资源(如数据库连接、日志系统、配置管理器)时尤为适合。

相关推荐
维天说1 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane19942 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
杨充2 小时前
11.DDD与战术建模
设计模式·开源·代码规范
杨充2 小时前
12.综合实战图片框架
设计模式·开源·代码规范
噢,我明白了2 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品2 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘2 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记3 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
糖果店的幽灵3 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph
极光代码工作室4 小时前
基于SpringBoot的在线博客系统
java·springboot·web开发·后端开发