1. 单例模式(Singleton)
1. 单例模式(Singleton)
问题:全局只需要一个实例(如配置、缓存、数据库连接)。
核心:用一个变量标记是否已创建过实例,如果有就直接返回。
class Singleton {
static #instance: Singleton | null = null;
constructor() {
if (Singleton.#instance) {
return Singleton.#instance;
}
Singleton.#instance = this;
}
}
const a = new Singleton();
const b = new Singleton();
console.log(a === b); // truepackage singleton
import "sync"
type singleton struct{}
var (
instance *singleton
once sync.Once
)
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}实战场景
- 全局配置中心:应用启动时读取一次环境变量、远程配置或构建配置,后续模块通过同一个配置对象读取,避免每个模块重复解析。
- 日志实例:服务端常见的
logger、tracer、metrics客户端通常全局共享,方便统一格式、采样率、上下文字段和输出目的地。 - 数据库连接池:真正共享的通常不是单个连接,而是连接池实例。业务代码都从同一个池里取连接,避免重复创建昂贵资源。
- 浏览器端 SDK:埋点、A/B 实验、Feature Flag、错误上报 SDK 初始化一次即可,页面组件只复用同一个客户端。
- 缓存管理器:内存缓存、LRU 缓存或本地缓存封装成单例,可以让多个模块共享同一份缓存状态。
- i18n 资源管理:语言包加载器、当前语言状态、格式化函数可以集中在一个实例里,避免页面各处各自维护语言状态。
- 依赖注入容器:后端服务或前端大型应用中,容器本身常常是单例,负责保存各种 service 的创建和生命周期。
- WebSocket 连接管理:聊天、协作编辑、实时通知类应用通常需要复用一个连接管理器,避免同一页面重复建立多个连接。
- 命令行工具上下文:CLI 启动后创建一个全局运行上下文,保存参数、输出器、配置和临时目录,后续命令共享它。
- 需要克制的地方:单例很容易变成隐藏的全局可变状态。适合放“确实全局唯一”的基础设施,不适合承载随请求、随用户变化的业务数据。
在 JS 中,模块本身天然就是单例——
import同一个模块,拿到的始终是同一个对象。