getInstance() 是否表示根据单例模式的单例?

Does getInstance() denote a singleton according the singleton pattern?

以前用过C#,我考虑过

Calendar cal = Calendar.getInstance();

根据 GoF Singleton pattern (Wikipedia) 成为单例方法,我想知道如何创建两个日历,因为 Date 有点过时了。

来自文档

Gets a calendar using the default time zone and locale.

和重载

getInstance(TimeZone zone)
getInstance(Locale aLocale)

在我看来,这似乎是单例模式的概括,可以为每个时区和语言环境创建一个单例。但我想要同一时区的两个日历。

然而,当我进行测试时

@Test
public void test()
{
    Calendar cal = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    assertTrue(cal == cal2); 
}

它失败了,告诉我这个 getInstance() 方法实际上 不是 单例模式 getInstance() 方法而是其他方法。

那么,根据Java中的单例模式,一般来说getInstance()是否表示单例?如果是,那么Java中的关键措辞是什么? Java 文档找出它 还是 不是 单身人士?如果不是,我如何识别 Java 中的单例模式?还是 Calendar 是唯一的例外?

我不想在每次遇到 getInstance() 电话时都进行单元测试。

我已阅读 this answer to "What is an efficient way to implement a singleton pattern in Java?",它的工作方式与在 C# 中完全相同,这与 Calendar 实现相矛盾。

不,如果你看the source code,你总是得到一个new Calendar,方法getInstace()只是决定你会得到哪种类型的Calendar

public static Calendar More ...getInstance(TimeZone zone, Locale aLocale)
{
    return createCalendar(zone, aLocale);
}

createCalendar

private static Calendar More ...createCalendar(TimeZone zone, Locale aLocale)
{
    // If the specified locale is a Thai locale, returns a BuddhistCalendar instance.
    if ("th".equals(aLocale.getLanguage())
        && ("TH".equals(aLocale.getCountry()))) {
        return new sun.util.BuddhistCalendar(zone, aLocale);  // new Budhist
    } else if ("JP".equals(aLocale.getVariant())
               && "JP".equals(aLocale.getCountry())
               && "ja".equals(aLocale.getLanguage())) {
        return new JapaneseImperialCalendar(zone, aLocale); // new Japanese
    }

    // else create the default calendar
    return new GregorianCalendar(zone, aLocale);   // new Gregorian
}

如何确定 java 中的单例?

Singletton returns 总是一个对象的同一个实例,有不同的方法,但通常你会有

  • Class属性(获取实例的对象)
  • 避免新创建的私有构造函数
  • Public getInstance 检查属性是否为空以创建它的方法,并且始终是对象的相同实例...

类似于:

public class Singleton {
    // instance attribute
    private static Singleton INSTANCE = null;

    // private constructor
    private Singleton() {}

    // public get that checks instance and return it
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

由于 Calendar.getInstance() 返回的对象引用了某个时间(更具体地说,是创建该对象的日期和时间),因此它不应该是单例的。如果是这种情况,则每次对它们执行操作时,所有对象都需要更新它们的基础date/time。

然而,根据我的理解,getInstance() 是名称,因为它是一个工厂方法。不需要直接创建实例,但是可以使用一定的方法指向任何date/time.

Calendar 不是单例,每次调用 Calendar.getInstance(...) return 都是一个不同的实例。 Javadoc 并没有说每次调用都会 return 相同的实例,因此您没有理由假设它会。

Calendar.getInstance(...)更符合工厂设计模式。

查看 getInstance 的其他示例,例如 Locale.getInstance(),您会看到 Javadoc 告诉您连续调用是否可能 return 同一个实例:

/**
 * Returns a <code>Locale</code> constructed from the given
 * <code>language</code>, <code>country</code> and
 * <code>variant</code>. If the same <code>Locale</code> instance
 * is available in the cache, then that instance is
 * returned. Otherwise, a new <code>Locale</code> instance is
 * created and cached.
 *
 * @param language lowercase two-letter ISO-639 code.
 * @param country uppercase two-letter ISO-3166 code.
 * @param variant vendor and browser specific code. See class description.
 * @return the <code>Locale</code> instance requested
 * @exception NullPointerException if any argument is null.
 */
static Locale getInstance(String language, String country, String variant)

同样,这不是单例,但正如 Javadoc 所说,实例已被缓存。除非 Javadoc 这么说,否则您可以预期每次调用 getInstance 到 return 都是不同的实例。

方法getInstance()通常表示java中的单例,但不是刻在岩石上的规则。确定它是单例的唯一方法,您必须查看文档(如果有)或更好的是实现。

没有

getInstance() 应该被用来表示一件事并且仅在 Java 中表示一件事,即您将获得给定 class 或其子[之一的实例=36=]es。 classes 和库之间是否适合单例模式或工厂模式差异很大。

根据我的经验 getInstance() 在标准库代码中 java.* 通常表示工厂模式,或者 configuring/subclassing 具有区域设置默认值的新实例(CalendarNumberFormatDateFormat 想到)或在给定一些参数的情况下查找预先存在的实例(想到 LocaleCurrency)。 在第三方库代码中可能有单例模式的趋势。

至于 Calendar.getInstance() 的细节,非参数变体将为您提供 Calendar 的子 class 实例(可能是 GregorianCalendar 之一, BuddhistCalendarJapaneseCalendar) 以及时区,具体取决于默认语言环境。带参数的 flavors 将允许您指定语言环境 and/or 时区而不是从默认值中提取。

如果返回的实例确实是单例或不是单例,是否缓存或具体实现。文档通常会指出返回的实例是否可变,如果可变,是否可以在线程之间安全地共享等等。