如何實現單例模式?

一、模式定義與核心價值

單例模式(Singleton Pattern)是一種創建型設計模式,保證一個類僅有一個實例,并提供全局訪問點。其核心價值在于:

  1. ??資源控制??:避免重復創建消耗性資源(如數據庫連接)
  2. ??狀態共享??:維護全局唯一狀態(如應用配置)
  3. ??訪問管控??:集中管理共享資源訪問(如日志系統)

二、經典實現方案對比

1. 閉包實現(ES5)

const Singleton = (() => {let instance = null;function createInstance() {// 私有方法和屬性const privateMethod = () => console.log('Private method');let privateVar = 'Initial value';return {// 暴露的公共接口publicMethod: () => {privateMethod();console.log('Public method called');},getVar: () => privateVar,setVar: (value) => { privateVar = value }};}return {getInstance: () => {if (!instance) {instance = createInstance();}return instance;}};
})();// 使用示例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true

2. 類靜態屬性(ES6+)

class DatabaseConnection {static instance = null;connectionCount = 0;constructor() {if (DatabaseConnection.instance) {return DatabaseConnection.instance;}// 模擬耗時的連接初始化this.connectionCount = 0;DatabaseConnection.instance = this;}connect() {this.connectionCount++;console.log(`Active connections: ${this.connectionCount}`);}disconnect() {this.connectionCount = Math.max(0, this.connectionCount - 1);}
}// 使用示例
const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();
db1.connect(); // Active connections: 1
db2.connect(); // Active connections: 2
console.log(db1 === db2); // true

3. 模塊模式(現代ES Module)

// config.js
let configInstance = null;export default class AppConfig {constructor() {if (!configInstance) {this.env = process.env.NODE_ENV || 'development';this.apiBase = this.env === 'production' ? 'https://api.example.com' : 'http://localhost:3000';configInstance = this;}return configInstance;}// 添加配置凍結防止修改freeze() {Object.freeze(this);}
}// 初始化并凍結配置
const config = new AppConfig();
config.freeze();

三、高級應用場景

1. 帶生命周期的單例

class SessionManager {static instance = null;static getInstance() {if (!this.instance) {this.instance = new SessionManager();// 注冊頁面卸載清理window.addEventListener('beforeunload', () => {this.instance.cleanup();});}return this.instance;}constructor() {this.sessions = new Map();this.timeouts = new Map();}createSession(userId, ttl = 3600) {const sessionId = crypto.randomUUID();this.sessions.set(sessionId, { userId, created: Date.now() });// 自動過期處理this.timeouts.set(sessionId, setTimeout(() => {this.destroySession(sessionId);}, ttl * 1000));return sessionId;}destroySession(sessionId) {clearTimeout(this.timeouts.get(sessionId));this.sessions.delete(sessionId);this.timeouts.delete(sessionId);}cleanup() {this.timeouts.forEach(clearTimeout);this.sessions.clear();this.timeouts.clear();}
}// 使用示例
const sessionManager = SessionManager.getInstance();
const sessionId = sessionManager.createSession('user123');

四、實踐建議與注意事項

1. 合理使用場景

? 適用場景:

  • 全局狀態管理(Redux/Vuex Store)
  • 瀏覽器環境唯一對象(如全屏加載器)
  • 共享資源訪問(IndexedDB連接池)

? 避免濫用:

  • 普通工具類(應使用純函數)
  • 短期使用的上下文對象(如表單數據)
  • 需要多實例的場景(如彈窗工廠)

2. 性能優化技巧

class OptimizedSingleton {static #instance; // 私有字段static #initialized = false;constructor() {if (!OptimizedSingleton.#initialized) {throw new Error('Use getInstance() method');}// 初始化邏輯...}static getInstance() {if (!this.#instance) {this.#initialized = true;this.#instance = new OptimizedSingleton();this.#initialized = false;}return this.#instance;}
}

3. 測試友好方案

// 可重置的單例模式
class TestableService {static instance;static reset() {this.instance = null;}constructor() {if (TestableService.instance) {return TestableService.instance;}// 初始化邏輯...TestableService.instance = this;}
}// 測試用例示例
describe('Service Test', () => {afterEach(() => {TestableService.reset();});test('instance equality', () => {const a = new TestableService();const b = new TestableService();expect(a).toBe(b);});
});

五、常見陷阱與解決方案

  1. ??模塊熱替換問題??
// 熱模塊替換兼容方案
if (module.hot) {module.hot.dispose(() => {Singleton.cleanup();});module.hot.accept();
}
  1. ??多窗口場景處理??
// 使用BroadcastChannel實現跨窗口單例
class CrossTabSingleton {static instance;static EVENT_KEY = 'singleton-update';constructor() {this.channel = new BroadcastChannel(CrossTabSingleton.EVENT_KEY);this.channel.onmessage = (event) => {if (event.data === 'instance-created') {// 處理其他頁面實例化的情況}};}static getInstance() {if (!this.instance) {this.instance = new CrossTabSingleton();this.instance.channel.postMessage('instance-created');}return this.instance;}
}
  1. ??內存泄漏預防??
class LeakSafeSingleton {static #weakRef;static getInstance() {let instance = this.#weakRef?.deref();if (!instance) {instance = new LeakSafeSingleton();this.#weakRef = new WeakRef(instance);// 注冊清理回調this.#registerFinalizer(instance);}return instance;}static #registerFinalizer(instance) {const registry = new FinalizationRegistry(() => {// 實例被GC回收后的處理console.log('Instance cleaned up');});registry.register(instance, 'instance');}
}

六、架構層面的思考

  1. ??依賴注入整合??
interface IService {operation(): void;
}class RealService implements IService {operation() {console.log('Real operation');}
}class SingletonService {private static instance: IService;static provide(impl?: new () => IService) {if (!this.instance) {this.instance = impl ? new impl() : new RealService();}return this.instance;}
}// 在應用入口
const service = SingletonService.provide();// 測試時可注入mock實現
class MockService implements IService {operation() {console.log('Mock operation');}
}
SingletonService.provide(MockService);
  1. ??微前端架構下的單例管理??
class FederatedSingleton {static instances = new Map();static register(name, instance) {if (!this.instances.has(name)) {this.instances.set(name, instance);}}static get(name) {if (!this.instances.has(name)) {throw new Error(`Instance ${name} not registered`);}return this.instances.get(name);}
}// 主應用注冊
FederatedSingleton.register('authService', new AuthService());// 子應用使用
const authService = FederatedSingleton.get('authService');

建議

  1. ??模式選擇策略??:

    • 簡單場景:使用模塊導出方案
    • 復雜生命周期:類靜態屬性實現
    • 測試需求:支持重置的變體
  2. ??性能考量??:

    • 高頻訪問場景使用直接對象訪問
    • 大數據量場景使用惰性加載
  3. ??架構演進??:

    • 預留擴展點(如二次初始化方法)
    • 考慮可能的集群化擴展需求

正確應用單例模式能夠有效管理系統中的特殊資源,但需要警惕其成為全局狀態污染的源頭。

在現代化前端架構中,建議結合DI容器或狀態管理庫使用,保持核心業務邏輯的純凈性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76762.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76762.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76762.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Three.js 系列專題 1:入門與基礎

什么是 Three.js? Three.js 是一個基于 WebGL 的 JavaScript 庫,它簡化了 3D 圖形編程,讓開發者無需深入了解底層 WebGL API 就能創建復雜的 3D 場景。它廣泛應用于網頁游戲、可視化、虛擬現實等領域。 學習目標 理解 Three.js 的核心組件:場景(Scene)、相機(Camera)…

藍橋云客---藍橋速算

3.藍橋速算【算法賽】 - 藍橋云課 問題描述 藍橋杯大賽最近新增了一項娛樂比賽——口算大賽,目的是測試選手的口算能力。 比賽規則如下: 初始給定一個長度為 N 的數組 A,其中第 i 個數字為 Ai?。隨后數組會被隱藏,并進行 Q 次…

Oracle遷移達夢遇中斷?試試SQLark的斷點續遷功能!

在企業級數據遷移項目中,如果遷移單表數據量超過億行、占用空間超過100GB時,一旦遇到網絡中斷或遷移報錯,往往需要整表重新遷移,導致效率低下,嚴重影響項目進度。針對這一痛點,SQLark 支持對 Oracle→DM 的…

【C/C++算法】藍橋杯之遞歸算法(如何編寫想出遞歸寫法)

緒論:沖擊藍橋杯一起加油!! 每日激勵:“不設限和自我肯定的心態:I can do all things。 — Stephen Curry” 緒論?: ———————— 早關注不迷路,話不多說安全帶系好,發車啦&am…

[ctfshow web入門] web5

前置知識 引用博客:phps的利用 當服務器配置了 .phps 文件類型時,訪問 .phps 文件會以語法高亮的形式直接顯示 PHP 源代碼,而不是執行它。.phps被作為輔助開發者的一種功能,開發者可以通過網站上訪問xxx.phps直接獲取高亮源代碼 …

day 8 TIM定時器

一、STM32 定時器概述 1. 定時器的概述定時器的基本功能,但是 STM32 的定時器除了具有定時功能之外,也具有定時器中斷功能,還具有輸入捕獲(檢測外部信號)以及輸出比較功能(輸出不同的脈沖)&…

Spring Boot 中使用 Redis:從入門到實戰

🌟 前言 歡迎來到我的技術小宇宙!🌌 這里不僅是我記錄技術點滴的后花園,也是我分享學習心得和項目經驗的樂園。📚 無論你是技術小白還是資深大牛,這里總有一些內容能觸動你的好奇心。🔍 &#x…

hi3516cv610通過menuconfig關閉的宏記錄

hi3516cv610通過menuconfig關閉的宏記錄 defconfig為 hi3516cv610_debug_defconfig或hi3516cv610_new_defconfig 1、 變為 2、 變為 3、 變為 4、 變為 5、 變為

WebSocket 詳解:構建一個復雜的實時聊天應用

文章目錄 一、前言二、WebSocket 基礎2.1 WebSocket 與 HTTP 的區別2.2 WebSocket 的優點 三、搭建 WebSocket 服務端3.1 安裝 ws 和 redis 庫3.2 創建 WebSocket 服務端3.3 創建用戶身份驗證 四、前端實現 WebSocket 客戶端4.1 創建 Vue 3 項目4.2 實現 WebSocket 連接和用戶注…

【JavaEE進階】Spring AOP入門

歡迎關注個人主頁:逸狼 創造不易,可以點點贊嗎 如有錯誤,歡迎指出~ AOP是Spring框架的第??核?(第??核?是 IoC) 什么是AOP? ? AspectOrientedProgramming(?向切?編程) 什么是?向切?編程呢? 切…

算法思想之雙指針(一)

歡迎拜訪:霧里看山-CSDN博客 本篇主題:算法思想之雙指針(一) 發布時間:2025.4.4 隸屬專欄:算法 目錄 雙指針算法介紹對撞指針:快慢指針: 例題移動零題目鏈接題目描述算法思路代碼實現 復寫零題目鏈接題目描…

【11408學習記錄】英語寫作黃金模板+語法全解:用FTC數據泄漏案掌握書信結構與長難句拆解(附思維導圖)

2025.04.04 英語寫作書信寫作第一段私人信件公務信函 語法總結——簡單句簡單句的核心:謂語動詞的變化詞性的拓展限定詞 形容詞與副詞介詞短語 成分的擴展同位語插入語 非謂語動詞 每日一句詞匯 第一步:辨別第二步:斷開第三步:簡化…

手機顯示5GA圖標的條件

最近有星友問在什么情況下才能顯示5G-A?雖然這個我也不知道,但是我有幾個運營商的5G終端白皮書,從上面就可以找到答案。 如上是幾個運營商顯示5G-A的條件,基本上考慮的都是3CC的情況,聯通還有考慮200M CA 2CC的場景&am…

網絡:華為數通HCIA學習:IP路由基礎

華為HCIA學習 IP路由基礎路由協議或路由種類以及對應路由的優先級按工作區域分類:按工作機制及算法分類:路由的優先級路由器選擇最優路由的順序是什么? 前言自治系統LAN和廣播域路由選路IP路由表路由度量建立路由表最長匹配原則路由器轉發數據包總結 IP…

Docker 鏡像相關的基本操作

一、Docker 鏡像基本操作 1. 查找鏡像 命令&#xff1a; docker search <鏡像名稱> 示例&#xff1a;查找 CentOS 鏡像&#xff1a; docker search centos 命令解釋&#xff1a; 默認從 Docker Hub 官方倉庫上搜索鏡像。搜索結果包含多個列&#xff1a; NAME&…

Linux文件特殊權限管理及進程和線程

acl 權限優先級 擁有者 > 特殊指定用戶 > 權限多的組 >權限少的組 > 其他 mask閾值 mask是能夠賦予指定用戶權限的最大閥值 當設定完畢文件的acl列表之后用chmod縮小了文件擁有組的權力 mask會發生變化 恢復&#xff1a; setfacl -m m: 權限 :rwx 文件/…

NVIDIA AgentIQ 詳細介紹

NVIDIA AgentIQ 詳細介紹 1. 引言 NVIDIA AgentIQ 是一個靈活的庫&#xff0c;旨在將企業代理&#xff08;無論使用何種框架&#xff09;與各種數據源和工具無縫集成。通過將代理、工具和代理工作流視為簡單的函數調用&#xff0c;AgentIQ 實現了真正的可組合性&#xff1a;一…

算法設計與分析5(動態規劃)

動態規劃的基本思想 將一個問題劃分為多個不獨立的子問題&#xff0c;這些子問題在求解過程中可能會有些數據進行了重復計算。我們可以把計算過的數據保存起來&#xff0c;當下次遇到同樣的數據計算時&#xff0c;就可以查表直接得到答案&#xff0c;而不是再次計算 動態規劃…

怎么理解量子比特模型,遷移到量子計算機開始編程

怎么理解量子比特模型&#xff0c;遷移到量子計算機開始編程 視頻鏈接&#xff1a; 好的現在是2025年的3月最后一天,3月31號,今天我們討論的話題是量子編程,也就是在量子計算機上,使用特定的語言進行軟件開發。當然我們要討論的,不是,量子編程的某一門語言的技術細節,而是考慮…

使用Expo框架開發APP——詳細教程

在移動應用開發日益普及的今天&#xff0c;跨平臺開發工具越來越受到開發者青睞。Expo 是基于 React Native 的一整套工具和服務&#xff0c;它能夠大幅降低原生開發的門檻&#xff0c;讓開發者只需關注業務邏輯和界面實現&#xff0c;而不用糾結于復雜的原生配置。本文將從零開…