设计模式-单例模式

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

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

相关推荐
UrbanJazzerati4 小时前
前端入门:margin居中、border、box-radius、transform、box-shadow、mouse事件、preventDefault()
前端·面试
蝎子莱莱爱打怪4 小时前
🚀🚀🚀嗨,一起来开发 开源IM系统呀!
前端·后端·github
Enddme4 小时前
《前端笔试必备:JavaScript ACM输入输出模板》
前端·javascript·面试
前端鱼4 小时前
前端面试中值得关注的js题
前端·面试
易元4 小时前
模式组合应用-外观模式
后端·设计模式
UnnamedOrange4 小时前
有来前后端部署
前端·后端
力Mer4 小时前
全排列-遇到的深浅拷贝问题
javascript
德育处主任4 小时前
p5.js 绘制 3D 椭球体 ellipsoid
前端·javascript·数据可视化
未来之窗软件服务4 小时前
未来之窗昭和仙君 (四) 前端网页分页 — 东方仙盟筑基期
前端·仙盟创梦ide·东方仙盟·东方仙盟修仙·昭和仙君
安卓开发者4 小时前
鸿蒙Next Web组件详解:属性设置与事件处理实战
前端·华为·harmonyos