Quotes: http://www.builder.com.cn/2007/0808/446992.shtml
Java Singleton 模式属于管理实例化过程的设计模式家族。 Singleton 是一个无法实例化的对象。这种设计模式暗示,在任何时候,只能由 JVM 创建一个 Singleton (对象)实例。
如果实例不存在,你通过创建类的新实例的方法建立一个类来执行这个模式;如果存在类的一个实例,就只会返回那个对象的一个引用。
Singleton 模式的运行机制
以下是 Singleton 模式的一个典型例子:
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
// Private constructor suppresses generation of
// a (public) default constructor
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
标准的 Singleton 模式并不使用直接静态变量实例化进行声明——它实例化构造器中的一个静态实例变量,而不查看它是否已经存在:
public class ClassicSingleton {
private static ClassicSingleton INSTANCE = null;
private ClassicSingleton() {
// Exists only to defeat instantiation.
}
public static ClassicSingleton getInstance() {
if(INSTANCE == null) {
INSTANCE = new ClassicSingleton();
}
return INSTANCE;
}
}
Singleton 类的默认构造器被设为私有,这样做可防止其它类使用 new 关键字直接将对象实例化。对返回 Singleton 对象的实例方法应用一个静态修饰符,这使得它成为一个类级方法,不创建对象即可进行访问。
何时需要使用 Singleton
当你只需要一个类实例时, Singleton 才真正有用;如果类拥有几个实例,使用 Singleton 就不再适用。
设计系统时,你通常希望控制对象的用法,防止用户(包括你自己)复制对象或建立新实例。例如,你可以使用它创建一个连接池。每次程序需要往数据库中写入内容时才创建一个新连接的做法并不明智;相反,一个或一组已经在池中的连接就可以使用 Singleton 模式实例化。
Singleton 模式常常和工厂方法模式一同使用,创建一个系统级资源,使用这个资源的代码并不知道它的特殊类型。抽象窗口工具包( AWT )就是组合使用这两个模式的典型例子。在 GUI 应用程序中,对每个应用程序实例,你一般只需要一个图形元素的实例,如打印 (Print) 对话框或 OK 按钮。
注意潜在的问题
虽然 Singleton 设计模式是最简单的设计模式之一,但它也存在一些缺陷。
多线程应用程序中的构造问题
在多线程应用程序中,你必须仔细构造 Singleton 模式。当 Singleton 不存在时,如果两个线程即将同时执行创建方法,这两个线程必须检查 Singleton 实例,但只有一个线程应当创建新对象。这个问题的典型解决办法就是对类使用相互排斥,指出对象正在被实例化。这是 Singleton 的一个线程安全的版本:
public class Singleton
{
// Private constructor suppresses generation
// of a (public) default constructor
private Singleton() {}
private static class SingletonHolder
{
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance()
{
return SingletonHolder.INSTANCE;
}
}
另一个解决办法是在 getInstance() 方法声明中添加 synchronized 关键字:
public static synchronized Singleton getInstance()
提前考虑克隆预防
你仍然可以使用对象的 clone() 方法克隆对象,建立一个 Singleton 对象。要禁用这一功能,你需要禁用对象的克隆方法,这产生一个 CloneNotSupportedException 例外。
public Object clone() throws
CloneNotSupportedException {
throw new CloneNotSupportedException();
}
考虑使 singleton 类位于最后
你可能希望将 Singleton 类放在最后,以避免 Singleton 的子类造成其它问题。
不要忘记垃圾收集
根据不同的执行,你的 Singleton 类和它的所有数据可能被当作垃圾收集。因此,在应用程序运行时,你必须保证存在一个 Singleton 类的实时引用。
结论
Singleton 模块得到广泛地使用,并证实可用于软件设计。虽然这个模式并非 Java 专有,但它已成为 Java 编程的一个典型应用。尽管这个模式相当简单,但还是要记住我在本文中描述的 Singleton 模式的限制。
Peter V. Mikhalenko 是一名通过 Sun 认证的专家,现在任德意志银行商业顾问。