单例模式

单例模式:在确有唯一实例约束时控制创建入口,并提供明确的访问边界

直觉:从变化压力出发,而不是从模式名称出发

任意模块各自创建注册表会产生版本分叉,但全局变量又隐藏依赖 因此,单例模式 的第一步不是画类图,而是写清 进程内配置快照只能有一个当前版本,但测试仍需替换其依赖 中哪项变化会扩散、现有结构怎样承担成本,以及什么观察足以拒绝模式。

在实验前先预测:沿 请求实例 → 检查现有值 → 创建或复用 → 读取快照 → 测试替换 运行时,哪条依赖最先暴露变化;随后只调整一个参与者或连接,保存代码结果和拒绝原因,最后重置到相同基线。

问题合同与术语

意图。 在确有唯一实例约束时控制创建入口,并提供明确的访问边界。适用边界。 唯一性是可证明的进程约束,并且生命周期、并发与测试替换都有方案。本页验收不变量是:同一进程版本下所有客户端读取到相同配置,同时测试可隔离替换

、、、、、

官方目录结构的逐项解释

下面的目录字段采用 GoF 模式目录的标准描述结构来组织独立讲解。每个字段都要连接当前问题、页面专属实验与练习证据;字段名称出现本身不算覆盖。

模式名称与分类

“单例模式”归入创建型模式,名称只用于定位 在确有唯一实例约束时控制创建入口,并提供明确的访问边界,不能替代问题证据。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

意图

“意图”回答模式想改变什么:在确有唯一实例约束时控制创建入口,并提供明确的访问边界。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

别名

“别名”在本页处理为:没有需要单独记忆的稳定别名;评审时使用目录中的正式名称,避免用近似称呼混淆责任。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

动机

“动机”从具体压力出发:任意模块各自创建注册表会产生版本分叉,但全局变量又隐藏依赖。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

适用性

“适用性”要求同时满足:唯一性是可证明的进程约束,并且生命周期、并发与测试替换都有方案。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

结构

“结构”由 ConfigRegistry、InstanceGuard、ConfigClient 以及它们之间的引用方向共同确定。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

参与者

“参与者”逐一说明 ConfigRegistry、InstanceGuard、ConfigClient 谁保存状态、谁发起调用以及谁承担变化。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

协作

“协作”的运行协议是:Registry 控制实例,Client 通过注入的访问器使用而不是随处读取全局。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

后果

“后果”必须连同收益和成本记录:统一实例容易,却会形成隐式全局状态、测试串扰和并发初始化风险。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

实现

“实现”落地时遵守:优先由组合根创建并注入;若懒加载,必须处理竞态、重置与资源释放。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

示例代码

“示例代码”使用本页 TypeScript 最小切片验证“同一进程版本下所有客户端读取到相同配置,同时测试可隔离替换”,代码是独立教学示例。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

已知应用

“已知应用”可在这些场景识别:硬件句柄或进程级注册表偶尔需要唯一所有权,但适用范围通常比想象小,但名称相似不构成采用证据。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

相关模式

“相关模式”用于比较边界:抽象工厂可控制产品族生命周期;依赖注入常是更透明的替代方案。 对“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”先保存基线,再改变一个条件;若出现“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”,就拒绝 单例模式 方案并回到更简单结构。

常见误区与反例

另一个易错点是把结构相似当作语义相同。抽象工厂可控制产品族生命周期;依赖注入常是更透明的替代方案;比较时必须同时写出谁触发变化、谁持有状态、失败如何传播,以及替代方案是否更小。

术语表

练习与答案

本章小结

单例模式 把“进程内配置快照只能有一个当前版本,但测试仍需替换其依赖”收敛为 ConfigRegistry、InstanceGuard、ConfigClient 的协作合同。学习结果不是能复述定义,而是能修改代码、触发“把普通服务做成单例来省传参,会隐藏依赖并阻碍并行测试”这一反例、重置实验,并根据 统一实例容易,却会形成隐式全局状态、测试串扰和并发初始化风险 接受或拒绝方案。

前后导航

讨论

评论区加载中…