荣耀的全球变量 - 成为一个荣耀的全球阶级.有人说打破面向对象的设计.
给我一些场景,除了好的旧记录器,使用单例是有意义的.
在我追求真相的过程中,我发现使用Singleton实际上很少有"可接受"的理由.
在互联网上一次又一次地出现的一个原因是"日志记录"类(你提到过).在这种情况下,可以使用Singleton而不是类的单个实例,因为项目中的每个类通常需要反复使用日志记录类.如果每个类都使用此日志记录类,则依赖项注入会变得很麻烦.
日志记录是"可接受的"Singleton的一个特定示例,因为它不会影响代码的执行.禁用日志记录,代码执行保持不变.启用它,同样相同.Misko在单根的根本原因中将其置于以下方式,"这里的信息以一种方式流动:从您的应用程序进入记录器.即使记录器是全局状态,由于没有信息从记录器流入您的应用程序,因此记录器是可接受的."
我相信还有其他正当理由.Alex Miller在" 模式我讨厌 "中讨论了服务定位器和客户端UI也可能是"可接受的"选择.
在Singleton阅读更多我爱你,但你让我失望.
Singleton候选人必须满足三个要求:
控制对共享资源的并发访问.
将从系统的多个不同部分请求访问资源.
只能有一个对象.
如果您提出的Singleton只有一个或两个这样的要求,重新设计几乎总是正确的选择.
例如,不太可能从多个位置("打印"菜单)调用打印机假脱机程序,因此您可以使用互斥锁来解决并发访问问题.
简单的记录器是可能有效的Singleton的最明显的例子,但是这可以随着更复杂的记录方案而改变.
读取应该只在启动时读取并将它们封装在Singleton中的配置文件.
您需要管理共享资源时使用单例.例如打印机假脱机程序.您的应用程序应该只有一个假脱机程序实例,以避免对同一资源的请求冲突.
或者数据库连接或文件管理器等.
只读单例存储一些全局状态(用户语言,帮助文件路径,应用程序路径)是合理的.小心使用单例来控制业务逻辑 - 单个几乎总是最终成为多个
管理数据库的连接(或连接池).
我还会用它来检索和存储外部配置文件的信息.
使用单例的一种方法是覆盖必须有一个"代理"控制对资源的访问的实例.单身人士在记录器方面表现优异,因为他们可以代理访问一个文件,这个文件只能写入.对于像日志记录这样的东西,它们提供了一种将写入抽象为日志文件的方法 - 你可以将缓存机制包装到你的单例等等......
还要考虑一种情况,你有一个应用程序有许多windows/threads/etc,但需要单点通信.我曾经用一个来控制我希望我的应用程序启动的作业.单身人员负责序列化工作并将其状态显示给感兴趣的程序的任何其他部分.在这种情况下,你可以看一个单例就像在你的应用程序中运行的"服务器"类...... HTH
在管理对整个应用程序共享的资源的访问时,应使用单例,并且可能具有同一类的多个实例是破坏性的.确保对共享资源线程安全的访问是这种模式至关重要的一个非常好的例子.
使用单身人士时,你应该确保你不会意外地隐藏依赖关系.理想情况下,单个应用程序(如应用程序中的大多数静态变量)在执行应用程序的初始化代码期间设置(静态void Main()用于C#可执行文件,static void main()用于java可执行文件)然后传入所有其他需要实例化的类.这有助于您保持可测试性.
我认为单例使用可以认为与数据库中的多对一关系相同。如果您的代码中有许多不同的部分需要使用一个对象的单个实例,那么使用单例才有意义。
单例的一个实际例子可以在Test :: Builder中找到,这个类几乎支持每个现代Perl测试模块.Test :: Builder singleton存储和代理测试过程的状态和历史(历史测试结果,计算运行测试的数量)以及测试输出的去向.这些都是协调由不同作者编写的多个测试模块在一个测试脚本中协同工作所必需的.
Test :: Builder的单身人士的历史是教育性的.调用new()
总是给你相同的对象.首先,所有数据都存储为类变量,对象本身没有任何内容.这一直有效,直到我想用自己测试Test :: Builder.然后我需要两个Test :: Builder对象,一个设置为虚拟对象,捕获并测试其行为和输出,一个是真正的测试对象.此时,Test :: Builder被重构为一个真实的对象.单例对象存储为类数据,并new()
始终返回它. create()
添加了一个新对象并启用测试.
目前,用户希望在自己的模块中更改Test :: Builder的某些行为,但是让其他人保持独立,而测试历史在所有测试模块中保持共同.现在发生的事情是单片Test :: Builder对象被分解成更小的片段(历史,输出,格式......),其中一个Test :: Builder实例将它们收集在一起.现在,Test :: Builder不再是一个单身人士.它的组成部分,如历史,可以.这将单身人士的灵活必要性推向了一个层次.它为用户提供了更多的混合和匹配件的灵活性.较小的单例对象现在可以只存储数据,其包含的对象决定如何使用它.它甚至允许非Test :: Builder类通过使用Test :: Builder历史记录和输出单例来进行.
似乎是在数据协调和行为灵活性之间存在推动和拉动,这可以通过将单例放在仅具有最小行为的共享数据来减轻,以确保数据完整性.
当您从数据库或文件中加载配置属性对象时,将其作为单例是有帮助的。没有理由继续读取服务器运行时不会改变的静态数据。