单例模式的实际应用是什么?

时间:2009-04-09 11:42:04

标签: c# design-patterns

复制

On design patterns: When should I use the singleton?

class Singleton
{
    private static Singleton instance;

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
                instance = new Singleton();

            return instance;
        }
    }
}

10 个答案:

答案 0 :(得分:16)

简单。单身人员做了什么?

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

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

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

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

换句话说,单身人士提供的两个功能实际上都是负面的。一般来说,我们希望我们的数据不会全局可见,而且我们希望无缘无故地带走灵活性。

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

我所见过的唯一真实世界的单身人士应用是“建筑师已阅读GoF书籍,并决定在任何地方填写设计模式。”或“一些卡在80年代的程序员不熟悉整个“面向对象”的东西,并希望在程序上进行编码,这意味着将数据存储为全局变量。而单例听起来像是一种“OOP”方式来制作全局变量而不会被大喊“。

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

答案 1 :(得分:8)

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

答案 2 :(得分:7)

Jon Skeet, THE_SKEET ,有一篇很好的文章举例说明了各种正确实现(线程安全,懒惰,高效)Singleton模式的方法。

转到read it here


根据大众需求(呃... 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();
    }
}
  

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:1)

假设您的问题在标题中:

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

答案 5 :(得分:1)

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

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

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

在C#等GC语言中,这可能无关紧要,但如果单例控制除了内存之外的其他资源,那么它确实很重要。您需要使用double-checked locking pattern来阻止它。

答案 6 :(得分:1)

当应该只有一个对象实例时,应该使用Singleton。 However, Misko Hevery has some thoughts on why Singletons are bad!

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:-1)

这不是单身,因为单身人士使用只读关键字提供线程安全性。

例如,

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;
        }
    }
}

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

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