2

我正在研究单例模式的这两种实现:

 Class Customer {

int x;
static int count = 0;

private Customer()
{
    x = 1;
}

public static Customer GetCustomer()
{
    if(count==0)
    {
        count++;
        return new Customer();
    }
    else
    {
        return null;
    }
}
}

实现 1,如果类已经实例化一次,则不调用构造函数。或者

 Class Customer{

int x;
static int count = 0;
public Customer()
{
    if(count == 0)
    {
        x = 1;
        count++;
    }
    else
    {
        return;
    }
}

实现 2,其中无论天气如何都调用构造函数,该类是否已实例化一次。我在网上观看了一个视频讲座,它说实现 2 不是首选,因为它为构造函数分配内存,尽管对象没有第二次实例化。我知道 Java 有自动垃圾收集,但只是想知道我在视频讲座中观看的内容是否相关。

4

2 回答 2

6

有人会说没有一个单例的实现是正确的,但我并不完全属于那个阵营。

人们经常倾向于不好地使用它们(例如,作为上帝的对象),但它们仍然有自己的位置(在我看来,这与这个答案无关)。

出于此答案的目的,我假设您在需要单身人士方面做出了正确的决定,但我确实敦促您阅读其潜在问题 - 很可能有更好的方法来实现您的目标。


话虽如此,我不确定您的代码示例是否正确。单例应该返回一个且只有一个实例,如果需要,创建一个,如果没有,则为您提供先前创建的一个。

我看不到您的第一个代码示例如何履行该合同。它会在第一次被调用时给你一个新的,然后它不会给你任何东西

而且您的第二个代码示例似乎根本无法阻止多个对象

因此,如果这是他们提供的教育质量,我会非常仔细地考虑您是否要继续观看该视频。


无论如何,我更喜欢只构造一次的那个,因为你应该只拥有该类的一个对象。换句话说,一个静态getMe()调用被正确同步以防止竞争条件允许创建多个Me对象,并且第一次创建一个新对象,在后续调用中返回相同的对象。

在伪代码中,这将是这样的:

class Me {
    private Me() {};

    private static Me *loner = NULL;

    public static synchronised Me *getMe() {
        if loner == NULL
            loner = new Me();
        return loner;
    }
}
于 2012-09-04T01:50:11.367 回答
0

写一个正确的单例并不容易。您需要注意竞争条件并防御反射攻击。例如,可以通过反射调用私有构造函数来创建对象的另一个实例。java中最简单和最安全的单例实现是通过枚举完成的:

enum Singleton {
    INSTANCE;
}

这是因为枚举常量被 JLS 指定为单例(JLS 的第 8.9 节):

枚举类型除了由其枚举常量定义的实例外,没有其他实例。

于 2012-09-04T04:57:23.090 回答