单例模式的真实世界应用是什么?

重复

关于设计模式:我什么时候应该使用单身人士?

class Singleton { private static Singleton instance; private Singleton() {} public static Singleton Instance { get { if (instance == null) instance = new Singleton(); return instance; } } } 

简单。 单身人员做什么?

  • 它提供对对象实例的全局访问,以及
  • 它保证永远不会创建该类型的一个实例。

所以当你需要这两件事时,你会使用单身人士。

这很少见。 全球通常都说不好。 我们倾向于尽可能避免使用它们。 并且围绕“如果存在多个实例,这是一个错误”的假设来构建应用程序是危险的,因为您通常会发现假设不成立。 也许您希望能够在本地创建多个实例,以用于缓存目的。 也许事实certificate,您需要多个数据库,多个日志,或者线程性能要求您为每个线程提供自己的实例。

在任何情况下,您都不需要强制执行“只有一个实例可能存在”的假设。 如果您只需要一个实例,只需创建一个实例。 但是将构造函数保持公开可见,以便在必要时可以创建更多实例。

换句话说,单身人士提供的两个function实际上都是负面的。 一般而言,我们不希望我们的数据全局可见,我们不希望无缘无故地剥夺灵活性。

如果确实需要单例提供的function之一,请实现一个function,而不需要另一个function。 如果您需要全局可访问的内容,请将其设置为全局。 不是单身人士。 如果你确实需要强制执行只存在一个实例(我想不出你想要这个的任何合理的情况),那么实现它,没有全局可见性。

我所见过的唯一真实世界的单身人士应用是“一位建筑师已经阅读过GoF书籍,并决定在任何地方设计模式。”或“一些陷入80年代的程序员对整体感到不舒服”面向对象的“事物,并且想要在程序上进行编码,这意味着将数据存储为全局变量。而单身人士听起来像是一种”OOP“方式来制作全局变量而不会被大喊”。

关键点在于,单身人士将两个非常不同的职责混合在一起。 通常,您最多需要任何给定对象中的一个。

Jon Skeet, THE_SKEET ,有一篇很好的文章举例说明了正确实现Singleton模式的各种方法(Thread safe,lazy,performant)。

去看看吧 。


根据大众需求(呃… downvote)我重现了Skeet版本:

 public sealed class Singleton { Singleton() { } public static Singleton Instance { get { return Nested.instance; } } class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } } 

这里,实例化是由对嵌套类的静态成员的第一次引用触发的,该静态成员仅在实例中发生。 这意味着实现完全是懒惰的,但具有以前的所有性能优势。 请注意,尽管嵌套类可以访问封闭类的私有成员,但反过来却不正确,因此需要在此处使用内部实例。 但是,这不会引起任何其他问题,因为这个类本身就是私有的。 但是,为了使实例化变得懒惰,代码有点复杂。

在我的项目中,我们创建了一个记录器组件,用于将应用程序登录到不同的源(例如,基于配置的文本文件,XML和数据库)。 因此,有一个日志管理器,它在应用程序中创建记录器类的唯一一个实例,用于记录消息,错误等。

我使用Singleton的一个很好的例子是在一个应用程序中,它必须从应用程序中的几个地方调用Web服务组件。 我需要维护状态,初始化一些字段,并维护一个调用和回调队列,所以我不能只进行静态调用。 但我希望在整个应用程序中只重用一个实例。 我将这个“服务”类实现为单例,以便我可以在应用程序上调用它来响应许多不同的事件,但它们都在一个地方处理。

根据我的经验,我使用单例,其中一个对象将在应用程序的生命周期中多次使用,需要初始化,和/或内存繁重。 基本上只有一个类的实例,你可能有很多实例,这样做成本很高。

假设您的问题在标题中:

我曾经使用过COM对象,每个服务器只能有一个实例。 我们通过单例将它暴露给整个ASP.NET应用程序。

请注意,此代码不是线程安全的:

 get { if (instance == null) instance = new Singleton(); return instance; } 

一个线程可以进入该函数,通过测试为null然后被暂停。 然后第二个线程可以启动并通过null测试。 从那时起,两个线程都会在某个时刻创建自己的sungleton对象副本,其中只有一个被使用。

在像C#这样的GC语言中,这可能并不重要,但如果单例控制除了内存之外的其他资源,那么它确实很重要。 您需要使用双重检查锁定模式来防止它。

当应该只有一个对象实例时,应该使用Singleton。 然而,Misko Hevery对Singletons为什么不好有一些想法!

如果您有一个资源需要花费很多时间来初始化,并且您使用多次,例如当您使用ORM或某种连接的对象上下文时,您可以发现单例模式很有用。

显然你必须注意保持那个东西活着并不比每次重建它都花费更多。

我使用单例的一种方法是为应用程序实现“主控制器”对象。 这有点像你用VBA获得的Application对象。

此对象执行各种启动和关闭任务。 它还提供了对应用程序范围设置和服务的访问。 这包括命令行参数和日志服务等的值。

这不是单例,因为单例为readonly关键字提供了线程安全性。

例如,

 public sealed class Singleton { // private static Singleton instance; (instead of this, it should be like this, see below) private static readonly Singleton instance = new Singleton(); static Singleton(){} private Singleton() {} public static Singleton Instance { get { if (instance == null) instance = new Singleton(); return instance; } } } 

通过使用它,它将提供胎面安全性和适当的单一模式(即它与静态类别的不同)。 你的单例代码不是线程安全的。

有关单身的更多信息,请查看以下链接: