【问题标题】:2 implementations of Singleton2 单例的实现
【发布时间】:2012-07-28 17:27:20
【问题描述】:

我知道在 java 中实现单例模式的两种方法,我想知道哪一种更好以及为什么。

第一种方式是:

  1. 声明类私有的构造函数
  2. 类中的所有内容都是静态的 - 基本上让类实例本身是单例

第二种方式是:

  1. 声明类private的构造函数
  2. 有一个静态成员来保存单例(可能是类的实例)
  3. 有一个静态的 getInstance() 方法

我倾向于认为即使第二种方法是最常见的,第一种方法可能会产生更好的代码可读性,这两种方法在运行时复杂性方面似乎同样有效,所以我真的不明白为什么第二种方法是方式的原因更常见且被认为是更好的做法...

启发我!

【问题讨论】:

    标签: java design-patterns static singleton


    【解决方案1】:

    第一种方法不是单例。 singleton 是一个类,其中只有一个实例,不能多也不能少。第一个东西有时被称为“静态类”、“实用程序类”或“不可实例化的类”。

    你可以用一个“真正的”单例来做很多你不能用实用程序类做的事情。例如,您可以有一个实现接口或扩展另一个类的单例;你不能用全静态方法来做到这一点。全静态方法类通常证明没有进行面向对象的设计分析

    至于在 Java 中实现单例模式有多少种方法,实际上有很多有趣的方法,使用不同的语言特性将初始化延迟到绝对需要时:类加载、枚举或只是一个同步块和if

    【讨论】:

    • 你可以通过静态方法使用类实例本身来实现相同的功能,不是吗?
    • 不,你不能。你可以有一个实现接口或扩展另一个类的单例——你不能用全静态方法来做到这一点。 all-static-methods 类通常证明没有进行面向对象的设计分析。
    • 你应该编辑你的答案并添加这个评论,你给了我一个很好的理由为什么第二种方法更有意义
    【解决方案2】:

    使用单例的其他类的可测试性受到静态方法的阻碍。使用实例,您可以替换模拟对象或其他形式的测试替身。

    【讨论】:

      【解决方案3】:

      基于对象的单例的优点

      1. 在任何可能无法想象的情况下,您的“单身人士”会成为非单身人士吗? 也许您需要按线程、按连接或其他分类? 2 号门让您拥有未来,无需重写代码。

      2. 您可能有一个单例,但您是否只有该单例的一个实现?一种常见的模式是让工厂方法查看运行时环境并确定单例提供的“服务”的哪个实现是合适的。 commons-logging LogFactory 就是这种类型的单例。

      【讨论】:

      • 说我很确定这是单身
      • 说我很确定每个人都会在几天/几周/几年内改变主意:-)
      【解决方案4】:

      如果我明白你的问题,对。

      为什么是#2

      public class MySingleton {
      
        static private MySingleton instance=new MySingleton();
      
        private MySingleton() {}
      
        static public MySingleton getInstance() { return instance; }
      
      }
      

      优于#1

      ...对不起,我没有明白第一点... -> 实际上是从其他 cmets 读取的,我明白了。我确认,拥有静态方法并不意味着你有一个单身人士。所以比较是不公平的;-/

      不管是什么,#2 更好的原因是因为多线程。当从静态初始化器初始化单例时,jvm 确保只有一个线程实例化该类。

      【讨论】:

        【解决方案5】:

        嗯,实现单例模式的有趣方法很少。让我回忆一下我读过的一些实现:

        1. 您在问题中提到的第二种方法。 (不是线程安全的)
        2. 当您开发多线程应用程序时,您可能必须使用锁(简单线程安全)

          公共密封类 Singleton { 静态单例实例=空; 静态只读对象挂锁 = new object();

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

          }

        3. 双重检查锁定

          公共密封类 Singleton { 静态单例实例=空; 静态只读对象挂锁 = new object();

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

          }

        4. 不是懒惰的,而是线程安全的,不使用锁

          公共密封类 Singleton { static readonly Singleton instance=new Singleton();

          // Explicit static constructor to tell C# compiler
          // not to mark type as beforefieldinit
          static Singleton()
          {
          }
          
          Singleton()
          {
          }
          
          public static Singleton Instance
          {
              get
              {
                  return instance;
              }
          }
          

          }

        5. 完全延迟初始化

          公共密封类 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();
          }
          

          }

        第三种方法在 java 中不起作用。Becos Java 内存模型不能确保构造函数在对新对象的引用分配给实例之前完成。

        希望对你有所帮助。

        【讨论】:

        • 所有这些都可以用java实现,因为它是一种设计模式..设计模式不受任何语言的约束!!只要是面向对象的程序语言都可以应用..
        【解决方案6】:

        也许考虑使用枚举实现单例:

        public enum Singleton {
        INSTANCE;
        
        public void doStuff() {
            System.out.println("Whoopee");
        }
        }
        

        并称它为Singleton.INSTANCE.doStuff()

        这是在 Josh Bloch 的《Effective Java》一书中推荐的

        【讨论】:

        • 我更注重代码的可读性,然后让我的程序运行速度快 1/1000 纳秒...
        • @OfekRon 好点。在这种情况下,我的观点是您的第一个案例的臃肿程度最低,并且最容易阅读
        • 正确,为了权衡一些可读性,您可以从不使用静态中获得不错的 OO 好处。 Java 枚举类型能够继承接口,也可以从 OO 中获益。实际上,它们是相同的
        猜你喜欢
        • 2013-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多