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認證的專家,現在任德意志銀行商業顧問。
責任編輯:德東