06-高级模式与实战项目——08. Singleton模式 - 单例服务

发布时间:2026/7/7 1:56:32
06-高级模式与实战项目——08. Singleton模式 - 单例服务 08. Singleton模式 - 单例服务概述Singleton 模式确保一个类只有一个实例并提供全局访问点。在 React 应用中常用于管理全局共享资源如 API 客户端、日志服务、状态存储等。维度内容What确保一个类只有一个实例的创建模式Why管理全局共享资源API 客户端、日志服务When需要全局唯一实例时Where服务层、工具类Who需要管理全局资源的开发者Howclass APIClient { static instance; static getInstance() {...} }1. 什么是 Singleton 模式1.1 基本概念Singleton 模式确保一个类只有一个实例并提供全局访问点。// 基础 Singleton class Singleton { constructor() { if (Singleton.instance) { return Singleton.instance; } Singleton.instance this; } static getInstance() { if (!Singleton.instance) { Singleton.instance new Singleton(); } return Singleton.instance; } } const instance1 new Singleton(); const instance2 new Singleton(); console.log(instance1 instance2); // true1.2 为什么需要 Singleton// ❌ 多个实例重复连接 const api1 new APIClient(); const api2 new APIClient(); // api1 和 api2 是不同的实例各自维护连接 // ✅ Singleton单一实例 const api1 APIClient.getInstance(); const api2 APIClient.getInstance(); console.log(api1 api2); // true2. 实现方式2.1 类式 Singletonclass APIClient { static instance null; constructor() { if (APIClient.instance) { return APIClient.instance; } this.baseURL process.env.API_URL; this.token null; APIClient.instance this; } static getInstance() { if (!APIClient.instance) { APIClient.instance new APIClient(); } return APIClient.instance; } setToken(token) { this.token token; } async request(endpoint, options {}) { const response await fetch(${this.baseURL}${endpoint}, { ...options, headers: { Content-Type: application/json, ...(this.token { Authorization: Bearer ${this.token} }), ...options.headers, }, }); return response.json(); } get(endpoint) { return this.request(endpoint, { method: GET }); } post(endpoint, data) { return this.request(endpoint, { method: POST, body: JSON.stringify(data) }); } } // 使用 const api APIClient.getInstance(); api.setToken(my-token); await api.get(/users);2.2 模块 Singleton// logger.js class Logger { constructor() { this.logs []; } log(message) { const entry { message, timestamp: new Date(), type: info }; this.logs.push(entry); console.log([INFO] ${message}); } error(message) { const entry { message, timestamp: new Date(), type: error }; this.logs.push(entry); console.error([ERROR] ${message}); } getLogs() { return this.logs; } } // 模块级别的单例 const logger new Logger(); export default logger; // 使用 import logger from ./logger; logger.log(应用启动);2.3 React Hook 中使用 Singleton// store.js class Store { static instance null; constructor() { if (Store.instance) return Store.instance; this.state {}; this.listeners new Set(); Store.instance this; } static getInstance() { if (!Store.instance) { Store.instance new Store(); } return Store.instance; } get(key) { return this.state[key]; } set(key, value) { this.state[key] value; this.notify(key); } subscribe(key, callback) { this.listeners.add({ key, callback }); } notify(key) { this.listeners.forEach(listener { if (listener.key key) { listener.callback(this.state[key]); } }); } } // 自定义 Hook function useStore(key) { const [value, setValue] useState(() Store.getInstance().get(key)); useEffect(() { const store Store.getInstance(); const handler (newValue) setValue(newValue); store.subscribe(key, handler); return () { // 取消订阅逻辑 }; }, [key]); const set (newValue) { Store.getInstance().set(key, newValue); }; return [value, set]; }3. 实际应用场景3.1 API 客户端class APIClient { static instance null; constructor() { if (APIClient.instance) return APIClient.instance; this.baseURL process.env.API_URL; this.interceptors { request: [], response: [] }; APIClient.instance this; } static getInstance() { if (!APIClient.instance) { APIClient.instance new APIClient(); } return APIClient.instance; } addRequestInterceptor(interceptor) { this.interceptors.request.push(interceptor); } addResponseInterceptor(interceptor) { this.interceptors.response.push(interceptor); } async request(endpoint, options {}) { let config { ...options }; // 执行请求拦截器 for (const interceptor of this.interceptors.request) { config interceptor(config); } const response await fetch(${this.baseURL}${endpoint}, config); let data await response.json(); // 执行响应拦截器 for (const interceptor of this.interceptors.response) { data interceptor(data); } return data; } } // 配置拦截器 const api APIClient.getInstance(); api.addRequestInterceptor((config) { const token localStorage.getItem(token); if (token) { config.headers { ...config.headers, Authorization: Bearer ${token}, }; } return config; }); // 使用 const api APIClient.getInstance(); const users await api.get(/users);3.2 事件总线class EventBus { static instance null; constructor() { if (EventBus.instance) return EventBus.instance; this.events new Map(); EventBus.instance this; } static getInstance() { if (!EventBus.instance) { EventBus.instance new EventBus(); } return EventBus.instance; } on(event, callback) { if (!this.events.has(event)) { this.events.set(event, []); } this.events.get(event).push(callback); } off(event, callback) { if (!this.events.has(event)) return; const callbacks this.events.get(event); const index callbacks.indexOf(callback); if (index ! -1) callbacks.splice(index, 1); } emit(event, data) { if (!this.events.has(event)) return; this.events.get(event).forEach(callback callback(data)); } once(event, callback) { const wrapper (data) { callback(data); this.off(event, wrapper); }; this.on(event, wrapper); } } // 使用 const bus EventBus.getInstance(); // 组件 A bus.on(user-login, (user) { console.log(用户登录:, user); }); // 组件 B bus.emit(user-login, { id: 1, name: 张三 });3.3 配置管理class ConfigManager { static instance null; constructor() { if (ConfigManager.instance) return ConfigManager.instance; this.config { apiUrl: process.env.API_URL, appName: process.env.APP_NAME, version: process.env.VERSION, features: {}, }; ConfigManager.instance this; } static getInstance() { if (!ConfigManager.instance) { ConfigManager.instance new ConfigManager(); } return ConfigManager.instance; } get(key) { return this.config[key]; } set(key, value) { this.config[key] value; } enableFeature(name) { this.config.features[name] true; } disableFeature(name) { this.config.features[name] false; } isFeatureEnabled(name) { return this.config.features[name] true; } getEnv() { return process.env.NODE_ENV; } isDev() { return this.getEnv() development; } isProd() { return this.getEnv() production; } } // 使用 const config ConfigManager.getInstance(); console.log(config.get(apiUrl)); config.enableFeature(newDashboard); if (config.isFeatureEnabled(newDashboard)) { // 显示新仪表盘 }4. 完整示例WebSocket 管理器class WebSocketManager { static instance null; constructor() { if (WebSocketManager.instance) return WebSocketManager.instance; this.socket null; this.handlers new Map(); this.reconnectAttempts 0; this.maxReconnectAttempts 5; WebSocketManager.instance this; } static getInstance() { if (!WebSocketManager.instance) { WebSocketManager.instance new WebSocketManager(); } return WebSocketManager.instance; } connect(url) { if (this.socket this.socket.readyState WebSocket.OPEN) { console.log(WebSocket 已连接); return; } this.socket new WebSocket(url); this.socket.onopen () { console.log(WebSocket 连接成功); this.reconnectAttempts 0; }; this.socket.onmessage (event) { const data JSON.parse(event.data); const handler this.handlers.get(data.type); if (handler) { handler(data.payload); } }; this.socket.onclose () { console.log(WebSocket 连接关闭); this.reconnect(url); }; this.socket.onerror (error) { console.error(WebSocket 错误:, error); }; } reconnect(url) { if (this.reconnectAttempts this.maxReconnectAttempts) { console.log(重连次数已达上限); return; } this.reconnectAttempts; const delay Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); setTimeout(() { console.log(尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})); this.connect(url); }, delay); } on(type, handler) { this.handlers.set(type, handler); } off(type) { this.handlers.delete(type); } send(type, payload) { if (this.socket this.socket.readyState WebSocket.OPEN) { this.socket.send(JSON.stringify({ type, payload })); } else { console.warn(WebSocket 未连接); } } disconnect() { if (this.socket) { this.socket.close(); this.socket null; } } } // React Hook function useWebSocket() { const [isConnected, setIsConnected] useState(false); const ws useMemo(() WebSocketManager.getInstance(), []); useEffect(() { ws.connect(wss://api.example.com/ws); const checkConnection setInterval(() { setIsConnected(ws.socket?.readyState WebSocket.OPEN); }, 1000); return () { clearInterval(checkConnection); }; }, [ws]); return { ws, isConnected }; } // 使用 function ChatComponent() { const { ws, isConnected } useWebSocket(); const [messages, setMessages] useState([]); useEffect(() { ws.on(message, (message) { setMessages(prev [...prev, message]); }); return () ws.off(message); }, [ws]); const sendMessage (text) { ws.send(message, { text, timestamp: Date.now() }); }; return ( div div状态: {isConnected ? 已连接 : 未连接}/div div classNamemessages {messages.map((msg, i) ( div key{i}{msg.text}/div ))} /div button onClick{() sendMessage(Hello)}发送/button /div ); }5. 总结核心要点要点说明核心价值确保全局唯一实例实现方式类单例、模块单例适用场景API 客户端、日志、配置、事件总线注意事项测试时可能需要重置记忆口诀单例模式全局一API 日志都能替共享资源统一管避免重复创实例6. 相关资源Singleton 模式JavaScript 单例模式