【问题标题】:Is the Singleton design pattern built into any frameworks?单例设计模式是否内置在任何框架中?
【发布时间】:2011-03-15 02:35:38
【问题描述】:

使用 Singleton 类可以保证一个类的实例将控制权交给程序员。真的很有用。

我想知道例如给定框架中是否存在单例接口来绕过显式创建/添加的需要?

贴花会很方便:

public sealed class MySingleton : ISingleton  //or a different class 
    { ... }

然后期望这个类只被实例化一次。

这是个好主意,还是我想的有点不对劲? :)

【问题讨论】:

  • 天哪……我们是否已经依赖于我们现在需要一个 ISingleton 的框架了!?
  • 大声笑这可能是懒惰,或者它可能会使代码更具可读性......

标签: c# java frameworks singleton


【解决方案1】:
public class Singleton<T> where T : class, new()
{
    static class SingletonCreator
    {
        internal static readonly T instance = new T();
    }

    public static T Instance
    {
        get
        {
            return SingletonCreator.instance;
        }
    }
}

它既懒惰又多才多艺。按需定义构造函数。

【讨论】:

    【解决方案2】:

    Ruby 有一个名为singleton 的模块,它使包含它的类成为单例。该模块内置于标准库中。

    【讨论】:

      【解决方案3】:

      .NET 4.0 具有Lazy(T) Class,它将在首次访问时以线程安全的方式延迟初始化一个值。 Lazy Initialization 话题有很多例子。

      此外,如果您使用的是Unity,则可以使用ContainerControlledLifetimeManager 配置lifetime manager,以确保单个实例。

      【讨论】:

        【解决方案4】:

        在 Java 中,您可以简单地使用枚举类型来做到这一点。您可以指定实例的数量,以便您选择没有(也称为实用程序类)、一个(也称为单例)或更多。

        public enum MySingleton {
            INSTANCE;
        } 
        

        【讨论】:

        • INSTANCE 究竟代表什么?对对象的引用?这个枚举是嵌套在实例类/对象还是静态类中?
        • 实例是唯一的枚举值/对象。它与定义一个 public static final MySingleton INSTANCE = new MySingleton(); 基本相同。带有私有构造函数。枚举可以嵌套也可以不嵌套。
        【解决方案5】:

        也许不是您想要的,但这是我最喜欢的 C# 中单例模式的版本。它是线程安全的,使用惰性实例化,并且不需要任何锁。编写起来也很轻松……不需要框架。 ;)

        class MyClass
        {
          // ...
          #region Singleton pattern
          private MyClass() { }
          public static MyClass Instance { get { return Singleton.instance; } }
          class Singleton
          {
            static Singleton() { }
            internal static readonly MyClass instance = new MyClass();
          }
          #endregion
          // ...
        }
        

        获取对象实例:

        MyClass m = MyClass.Instance;
        

        【讨论】:

          【解决方案6】:

          Google Guice 是一个依赖注入框架,支持 @Singleton 注释。

          请注意,使用 @Singleton 注释的类不是“真正的”单例 - 没有什么可以阻止客户端代码创建此类类的许多实例。但是,Guice 管理的依赖项都将共享同一个实例。

          http://code.google.com/p/google-guice/wiki/Scopes

          【讨论】:

          • 为什么 Guice 链接上的评论会出现“手动单例错误”? “如果您现在想为每个 JVM 提供一个类型实例,我建议您推出自己的 Scope 实现。尽量远离手动单例:它们容易出错并且使您的代码更难测试。所以 guice 不支持真正的单例”
          • 出于 BalusC 链接到的文章中讨论的原因。
          【解决方案7】:

          单例模式背后的意图是“配置一次,多次使用”。这通常用于共享上述答案之一中提到的任何类型的数据或资源。但启用任何类型的“管理”应用程序也很有用。 (如果是 Java,请考虑 JMX)

          您有一个可以多次使用的特定类的实例。由于只有一个实例,通过适当地配置该实例,您可以反映整个应用程序的配置更改。因此,单例模式可以为您的应用启用“管理仪表板”。

          Spring 或 Spring.NET(Spring 的 .NET 实现)对于配置和注入单例非常有用。相同的论点适用于任何类型的依赖注入框架。您应该阅读有关依赖注入的一般信息以利用全部功能。跨多个 JVM 或集群的真正单例通常更难创建和管理。并且可能需要工具支持。在实践中,没有必要创建和维护它。

          不要将单例与静态混淆!构造看起来很相似,但可能有很大不同。现在来敲我自己的小号! Here 是我写的一篇关于静态方法的文章的链接。

          【讨论】:

          • 您的文章很好地反对使用静态。它似乎被用作“修复”,后来又后悔了。 +1
          • “不要将单例与静态混淆!”难以置信。
          • 不是混淆,而是忘记了在我的特定项目中有效的方法。
          【解决方案8】:

          我想知道例如给定框架中是否存在单例接口来绕过显式创建/添加的需要?

          它不存在,也不可能存在。单例基本上需要static Singleton getInstance()方法,但是因为是static,所以不能定义为抽象(接口)方法。这也是有道理的,只能有 一个 单例实现,而不是多个。抽象它是没有意义的。

          您需要自己对完整的单例进行样板化。然而,我强烈质疑这有什么用。防止堆栈溢出或内存错误当然不是其唯一目的。编写 good 代码可以防止这种情况。仅当您希望最终用户始终处理 same 实例时,单例才有用。顺便说一句,没有单例模式也可以做到这一点。要么直接声明它static,要么利用普通框架可以为您提供的“应用程序范围”概念。

          而不是单例,而是寻找inversion of control(依赖注入)。顺便说一句,这也正是 Spring 正在做的事情。他们不使用“纯”单例。他们的用词很糟糕。

          另见:

          【讨论】:

          • 我认为微软认为单身人士是邪恶的,我对吗?他们甚至不会实现现在存在于 Java 中的“虚拟单例”。我不确定我能否看到明智地使用它们的问题。
          • 另外,虽然我的知识有限......单例是实例,并在运行时提供对象继承的好处。这不是真的吗?
          • 单例在 OOP 中是邪恶的。继承在单例中毫无意义,因为它是静态的和最终的。你不能从它扩展,也不能抽象它。你不能替换或模拟它。也没有多态性。它又继承自 Object 基本上是您可以实例化它的唯一优势。
          【解决方案9】:

          Singleton 不能防止堆栈溢出,不知道你在做什么。

          对于 Java,想到的是 Spring。默认情况下,您编写的每个 Spring bean 都是一个单例。你可以在 100 个地方使用它,它们都将通过注入自动设置,所有 100 个引用都将指向同一个对象(即单例)。当你在 Spring 中建立一个项目时,你可以按照约定将任何你想要的类设为单例。

          【讨论】:

          • 我的意思是,如果一个应用程序成功地实例化一个类太多次,最终堆栈将耗尽引用空间。对吗?
          • Spring 非常有趣。我一定会调查的。有兴趣看看是否有 .NET 等价物。
          • @AlexW - 错误。实例化对象会导致堆栈溢出的唯一方法是构造函数递归实例化同一类的实例。这与单例模式无关,
          • 严格来说 Spring bean 不是单例的。相反,它们是每个 Spring 上下文的一个实例。但是,您只会在以下情况下注意到区别: 1) webapp 重新启动,或 2) 如果同一个类被多个 webapps 使用;即通过一个通用的类加载器。 (后者需要一些工作,因为 webapps 通常使用不同的类加载器。所以“相同”的类通常是不同的......在 web 容器中的 webapps 之间。)
          • 使用单例来管理内存有点不对劲——这不是真正的目的。真正的目的是防止多个实例存在,共享资源、公共数据等。事实上,它有点反模式,往往会导致代码难以测试。最好不要将类的行为与其实例化的逻辑结合起来。
          猜你喜欢
          • 2010-11-14
          • 2012-02-05
          • 1970-01-01
          • 1970-01-01
          • 2017-10-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-03
          相关资源
          最近更新 更多