设计模式-单例模式

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

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

相关推荐
passerby606110 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅11 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment11 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte12 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc