日常开发,单例设计模式是解决常用的设计模式之一。今天我们来深入探讨单例模式(Singleton Pattern),这个看似简单却应用广泛的设计模式。
什么是单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
核心特征:
- 全局唯一性:整个应用程序中只存在一个实例
- 延迟实例化:通常在第一次使用时才创建实例
- 全局访问:提供静态方法获取实例
单例模式的几种实现方式
1. 饿汉式(Eager Initialization)
js
class EagerSingleton {
private static instance = new EagerSingleton();
private constructor() {}
static getInstance(): EagerSingleton {
return EagerSingleton.instance;
}
}
特点: 类加载时就创建实例,线程安全但可能浪费内存。
2. 懒汉式(Lazy Initialization)
js
class LazySingleton {
private static instance: LazySingleton;
private constructor() {}
static getInstance(): LazySingleton {
if (!LazySingleton.instance) {
LazySingleton.instance = new LazySingleton();
}
return LazySingleton.instance;
}
}
特点: 第一次使用时才创建,节省内存但需考虑线程安全。
3. 双重检查锁定(Double-Checked Locking)
js
class DoubleCheckSingleton {
private static instance: DoubleCheckSingleton;
private static creating = false;
private constructor() {}
static getInstance(): DoubleCheckSingleton {
if (!DoubleCheckSingleton.instance) {
if (!DoubleCheckSingleton.creating) {
DoubleCheckSingleton.creating = true;
DoubleCheckSingleton.instance = new DoubleCheckSingleton();
DoubleCheckSingleton.creating = false;
}
}
return DoubleCheckSingleton.instance;
}
}
前端业务中的真实使用场景
1. 用户信息管理
js
// 实名信息单例对象
export class UserInfo {
private static instance: UserInfo;
id: string = '';
account: string = '';
realname: string | null = null;
// ... 其他属性
private constructor() {
// 私有构造函数防止外部实例化
}
static getInstance(): UserInfo {
if (!UserInfo.instance) {
UserInfo.instance = new UserInfo();
}
return UserInfo.instance;
}
updateFromResponse(data: any): void {
this.id = data.id || this.id;
this.account = data.account || this.account;
// ...
}
clear(): void {
this.id = '';
this.account = '';
// ...
}
}
// 使用
const userInfo = UserInfo.getInstance();
userInfo.updateFromResponse(apiResponse);
2. 全局配置管理
js
class AppConfig {
private static instance: AppConfig;
private config = {
apiBaseUrl: '',
theme: 'light',
language: 'zh-CN'
};
static getInstance() {
if (!AppConfig.instance) {
AppConfig.instance = new AppConfig();
}
return AppConfig.instance;
}
setConfig(key: string, value: any) {
this.config[key] = value;
}
getConfig(key: string) {
return this.config[key];
}
}
3. 事件总线
js
class EventBus {
private static instance: EventBus;
private events: Map<string, Function[]> = new Map();
static getInstance() {
if (!EventBus.instance) {
EventBus.instance = new EventBus();
}
return EventBus.instance;
}
on(event: string, callback: Function) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)!.push(callback);
}
emit(event: string, data?: any) {
const callbacks = this.events.get(event);
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
4. 缓存管理器
js
class CacheManager {
private static instance: CacheManager;
private cache = new Map<string, { data: any, expiry: number }>();
static getInstance() {
if (!CacheManager.instance) {
CacheManager.instance = new CacheManager();
}
return CacheManager.instance;
}
set(key: string, data: any, ttl = 5 * 60 * 1000) {
this.cache.set(key, {
data,
expiry: Date.now() + ttl
});
}
get(key: string) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}
return item.data;
}
}
SSM框架中的单例模式
最近又想复习一下SSM,所以也顺带讲一下SSM中的单例模式
1. Spring 中的单例
Spring 容器中的 Bean 默认是单例的(只是默认):
js
@Service
public class UserService {
// Spring 容器保证全局唯一
}
@Component
@Scope("singleton") // 显式声明单例
public class ConfigService {
}
2. MyBatis 中的单例
js
// SqlSessionFactory 通常作为单例使用
public class MyBatisConfig {
private static SqlSessionFactory sqlSessionFactory;
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
// 初始化逻辑
}
return sqlSessionFactory;
}
}
3. 数据库连接池
js
public class DatabasePool {
private static volatile DatabasePool instance;
private DataSource dataSource;
private DatabasePool() {
// 初始化连接池
}
public static DatabasePool getInstance() {
if (instance == null) {
synchronized (DatabasePool.class) {
if (instance == null) {
instance = new DatabasePool();
}
}
}
return instance;
}
}
单例模式的优缺点
优点
- 内存节省:避免重复创建对象
- 全局访问:提供统一的访问入口
- 状态共享:便于在不同模块间共享状态(这个其实在react中也是非常好用的)
- 延迟加载:按需创建,提高启动性能
单例模式在开发中还是非常常见的,至少一个项目中是有好几处的,然后了解设计模式也能提高编程思维,合适的时候用合适的算法,不要过度使用,明明不适合非常那些写,那么写出来也是十扇,永远以确保代码的可维护性和可测试性为标准编写代码。