单例模式
Singleton Pattern
创建型模式📖 模式定义
单例模式确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式在需要控制资源访问、协调系统行为或确保某些组件只有一个副本时非常有用。
🎯 解决的问题
- 资源控制:确保某些昂贵的资源(如数据库连接、文件系统、网络连接)只被创建一次
- 全局状态管理:提供一个全局访问点来管理应用程序的状态
- 协调行为:确保系统中某些组件的行为是协调一致的
- 缓存管理:管理全局缓存,避免重复创建相同的对象
💻 代码实现
Java 实现(线程安全的懒汉式)
Java
public class Singleton {
// 使用 volatile 关键字确保多线程环境下的可见性
private static volatile Singleton instance;
// 私有构造函数,防止外部实例化
private Singleton() {
// 防止反射攻击
if (instance != null) {
throw new RuntimeException("请使用 getInstance() 方法获取实例");
}
}
// 双重检查锁定(Double-Checked Locking)
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
// 业务方法
public void doSomething() {
System.out.println("单例对象正在执行业务逻辑...");
}
}
Python 实现(装饰器方式)
Python
def singleton(cls):
"""单例装饰器"""
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self):
self.connection = None
print("创建数据库连接...")
def connect(self):
if not self.connection:
self.connection = "已连接到数据库"
return self.connection
def query(self, sql):
return f"执行查询: {sql}"
# 使用示例
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True,同一个实例
JavaScript 实现(ES6 类)
JavaScript
class Singleton {
constructor() {
// 如果已经存在实例,返回现有实例
if (Singleton.instance) {
return Singleton.instance;
}
// 初始化实例
this.data = [];
this.timestamp = Date.now();
// 保存实例引用
Singleton.instance = this;
// 冻结实例,防止修改
Object.freeze(this);
}
addData(item) {
this.data.push(item);
}
getData() {
return this.data;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// 使用示例
const instance1 = new Singleton();
const instance2 = new Singleton();
const instance3 = Singleton.getInstance();
console.log(instance1 === instance2); // true
console.log(instance1 === instance3); // true
✅ 优点
- 控制实例数量:确保类只有一个实例
- 全局访问:提供全局访问点
- 延迟初始化:可以在需要时才创建实例
- 节省资源:避免重复创建昂贵的对象
- 状态一致性:确保全局状态的一致性
❌ 缺点
- 违反单一职责:既要管理实例创建又要处理业务逻辑
- 难以测试:全局状态使单元测试变得困难
- 隐藏依赖:代码依赖关系不够明确
- 线程安全:多线程环境下需要特殊处理
- 扩展困难:难以继承和扩展
🔧 适用场景
- 数据库连接池:管理数据库连接,避免频繁创建和销毁连接
- 日志记录器:全局日志管理,确保日志输出的一致性
- 配置管理:应用程序配置信息的全局访问点
- 缓存管理:全局缓存系统,避免重复计算
- 线程池:管理应用程序的线程资源
- 设备驱动:硬件设备的访问控制
⚠️ 注意事项
- 线程安全:在多线程环境下要确保线程安全
- 反射攻击:防止通过反射机制破坏单例
- 序列化问题:序列化和反序列化可能创建新实例
- 类加载器:不同类加载器可能创建不同实例
- 内存泄漏:单例对象持有的引用可能导致内存泄漏
🔄 相关模式
- 工厂模式:可以使用工厂模式来创建单例对象
- 抽象工厂模式:抽象工厂本身可以是单例
- 建造者模式:建造者可以是单例
- 原型模式:原型注册表可以是单例