0

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

第一种方法是:

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

第二种方法是:

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

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

开导我!

4

6 回答 6

5

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

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

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

于 2012-07-31T01:07:28.853 回答
3

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

于 2012-07-31T01:16:00.117 回答
1

基于对象的单例的优点

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

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

于 2012-07-31T01:08:38.463 回答
0

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

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

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

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

    }

  3. 双重检查锁定

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

    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 { 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 内存模型不能确保构造函数在对新对象的引用分配给实例之前完成。

希望这对您有所帮助。

于 2012-07-31T04:57:59.593 回答
0

如果我得到你的问题,对。

为什么这是#2

public class MySingleton {

  static private MySingleton instance=new MySingleton();

  private MySingleton() {}

  static public MySingleton getInstance() { return instance; }

}

优于#1

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

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

于 2012-07-31T01:11:50.100 回答
-2

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

public enum Singleton {
INSTANCE;

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

并称它为Singleton.INSTANCE.doStuff()

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

于 2012-07-31T01:07:11.350 回答