设计模式-单例模式

日常开发,单例设计模式是解决常用的设计模式之一。今天我们来深入探讨单例模式(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中也是非常好用的)
  • 延迟加载:按需创建,提高启动性能

单例模式在开发中还是非常常见的,至少一个项目中是有好几处的,然后了解设计模式也能提高编程思维,合适的时候用合适的算法,不要过度使用,明明不适合非常那些写,那么写出来也是十扇,永远以确保代码的可维护性和可测试性为标准编写代码。

相关推荐
折果1 小时前
如何在vue项目中封装自己的全局message组件?一步教会你!
前端·面试
不死鸟.亚历山大.狼崽子1 小时前
Syntax Error: Error: PostCSS received undefined instead of CSS string
前端·css·postcss
汪子熙1 小时前
Vite 极速时代的构建范式
前端·javascript
叶常落1 小时前
[react] js容易混淆的两种导出方式2025-08-22
javascript
跟橙姐学代码1 小时前
一文读懂 Python 的 JSON 模块:从零到高手的进阶之路
前端·python
前端小巷子1 小时前
Vue3的渲染秘密:从同步批处理到异步微任务
前端·vue.js·面试
nightunderblackcat2 小时前
新手向:用FastAPI快速构建高性能Web服务
前端·fastapi
小码编匠2 小时前
物联网数据大屏开发效率翻倍:Vue + DataV + ECharts 的标准化模板库
前端·vue.js·echarts
欧阳天风3 小时前
分段渲染加载页面
前端·fcp
艾小码3 小时前
TypeScript在前端的实践:类型系统助力大型应用开发
前端·typescript