Java设计模式 二十六 工厂模式 + 单例模式
工厂模式 + 单例模式
工厂模式和单例模式的组合是一种常见的设计模式组合,通常用于确保某些全局共享的资源(如配置管理器、数据库连接池等)只有一个实例,同时通过工厂方法提供统一的对象创建方式。
1. 场景说明
工厂模式用于创建对象,提供了一种灵活的对象实例化方式。单例模式用于确保某个类只有一个实例,并提供全局访问点。两者的结合通常应用于以下场景:
- 数据库连接工厂: 确保数据库连接池只有一个工厂实例,同时提供连接对象的创建。
- 配置管理器: 确保配置管理器类只有一个实例,通过工厂方法管理不同的配置对象。
- 日志系统: 确保日志管理器只有一个实例,同时根据需要生成不同类型的日志记录器。
2. 模式组合的优点
- 唯一性: 单例模式保证工厂类的唯一性,避免了工厂类被多次实例化。
- 扩展性: 工厂模式为创建对象提供了灵活性,可以通过多态或其他扩展方式动态创建不同类型的对象。
- 全局访问: 单例模式提供了全局访问点,工厂模式集中管理对象的创建逻辑,二者结合使得系统结构清晰。
3. 实现示例:数据库连接工厂
以下示例展示了一个数据库连接工厂的实现,工厂类采用单例模式,确保只有一个工厂实例。
(1) 数据库连接类
数据库连接类表示单个连接对象。
// 数据库连接类
public class DatabaseConnection {
private String connectionString;
public DatabaseConnection(String connectionString) {
this.connectionString = connectionString;
}
public void connect() {
System.out.println("连接到数据库: " + connectionString);
}
}
(2) 工厂类
工厂类使用单例模式,确保只有一个工厂实例,负责创建数据库连接对象。
// 工厂类
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) 客户端代码
客户端代码通过单例工厂创建数据库连接对象。
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) 日志记录器接口
// 日志记录器接口
public interface Logger {
void log(String message);
}
(2) 具体日志记录器
// 文件日志记录器
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) 单例工厂类
// 日志工厂类
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) 客户端代码
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. 优缺点
优点:
- 全局唯一性: 单例模式确保工厂类唯一,全局共享。
- 灵活扩展: 工厂模式使得对象创建逻辑集中在工厂类中,新增对象类型时无需修改客户端代码。
- 高效管理: 工厂和单例结合能够高效管理系统中的全局资源,例如数据库连接、日志管理器等。
缺点:
- 复杂性增加: 模式组合会增加系统的复杂度,可能引入过度设计的问题。
- 线程安全性: 单例模式需要考虑多线程环境下的安全性,增加了实现的复杂性。
6. 总结
工厂模式 + 单例模式的组合是一种常见的设计模式组合,用于解决全局唯一资源的创建和管理问题。通过将工厂类设计为单例,我们可以确保全局共享的工厂实例,同时通过工厂模式灵活创建不同类型的对象。这种组合在实际开发中非常实用,特别是在需要集中管理全局资源(如数据库连接、日志系统、配置管理器)时尤为适合。