目录
意图
- 确保一个类只有一个实例,并提供一个全局访问点。
- 封装的“即时初始化”或“首次使用初始化”。
问题
应用程序需要一个,而且只有一个,对象的实例。此外,延迟初始化和全局访问也是必要的。
讨论
使单个实例对象的类负责创建、初始化、访问和执行。将实例声明为私有静态数据成员。提供一个封装所有初始化代码的公共静态成员函数,并提供对实例的访问。
每当需要引用单个实例时,客户端都会调用访问器函数(使用类名和范围解析运算符)。
仅当满足以下所有三个条件时才应考虑单例:
- 无法合理分配单个实例的所有权
- 延迟初始化是可取的
- 未另外提供全球访问权限
如果单个实例的所有权、初始化发生的时间和方式以及全局访问都不是问题,那么 Singleton 就不够有趣。
可以扩展单例模式以支持访问特定于应用程序数量的实例。
“静态成员函数访问器”方法不支持 Singleton 类的子类化。如果需要子类化,请参阅书中的讨论。
删除单例类/实例是一个不平凡的设计问题。有关讨论,请参阅 John Vlissides 的“杀死一个单身人士”。
结构

使单个实例的类负责访问和“首次使用时初始化”。单个实例是私有静态属性。访问器函数是一个公共静态方法。

例子
单例模式确保一个类只有一个实例,并提供对该实例的全局访问点。它以单例集命名,单例集被定义为包含一个元素的集合。美国总统的办公室是辛格尔顿。美国宪法规定了总统的选举方式、任期限制和继任顺序。因此,在任何给定时间最多只能有一位在职总统。无论现任总统的个人身份如何,“美国总统”这个头衔都是一个全球性的访问点,可以识别办公室里的人。

检查清单
- 在“单一实例”类中定义一个私有
static
属性。 - 在类中定义一个公共
static
访问器函数。 - 在访问器函数中执行“延迟初始化”(首次使用时创建)。
- 将所有构造函数定义为
protected
orprivate
。 - 客户端只能使用访问器函数来操作 Singleton。
经验法则
- Abstract Factory、Builder 和 Prototype 可以在它们的实现中使用 Singleton。
- 外观对象通常是单例,因为只需要一个外观对象。
- 状态对象通常是单例。
- Singleton 相对于全局变量的优势在于,当您使用 Singleton 时,您绝对可以确定实例的数量,并且您可以改变主意并管理任意数量的实例。
- Singleton 设计模式是使用最不恰当的模式之一。当一个类必须只有一个实例时使用单例,不多也不少。设计人员经常使用单例来替代全局变量。出于意图和目的,Singleton 是一个全局变量。Singleton 并没有取消全局;它只是重命名它。
- 什么时候不需要 Singleton?简短的回答:大多数时候。长答案:将对象资源作为对需要它的对象的引用而不是让对象全局访问资源更简单。单例的真正问题在于,它们给了你一个很好的借口,让你不用仔细考虑对象的适当可见性。在物体的暴露和保护之间找到适当的平衡对于保持灵活性至关重要。
- 我们小组有一个使用全局数据的坏习惯,所以我做了一个关于 Singleton 的学习小组。接下来我知道单例无处不在,并且与全局数据相关的问题都没有消失。全球数据问题的答案不是“让它成为单例”。答案是,“你到底为什么要使用全球数据?” 更改名称不会改变问题。事实上,它可能会让情况变得更糟,因为它让你有机会说,“好吧,我不这样做,我正在这样做”——尽管这和那是一回事。
本文来自转载,原文链接: