單例模式
通過單例模式可以保證系統中一個類只有一個實例而且該實例易於被外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決辦法。
模式動機與定義
對系統中某些類來說,只有一個實例很重要,例如,一個系統只能有一個窗口管理器或文件系統。因此確保系統中某個對象的唯一性即一個類只能有一個實例很重要。
單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例,這個類稱爲單例類,它提供全局訪問方法。單例模式有三個要點:一是某個類只能有一個實例;二是它必須自行創建這個實例;三是它必須自行向整個系統提供這個實例。
模式分析
單例模式的目的是保證類僅有一個實例,並提供一個訪問它的全局訪問點。單例類擁有一個私有構造函數,確保用戶無法通過new關鍵字直接實例化。除此之外,該模式包含一個靜態私有成員變量與靜態公有的工廠方法,該工廠方法負責校驗實例存在性並實例化自己,然後存儲在靜態成員變量中,以確保只有一個實例被創建。因此在單例模式的實現過程中要注意三點:
- 單例類的構造函數爲私有
- 提供一個自身的靜態私有成員變量
- 提供一個公有的靜態工廠方法
public class Singleton {
private static Singleton instance = null;
//私有構造方法
private Singleton() {
}
//靜態公有工廠方法,返回唯一實例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Client {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
餓漢式單例類和懶漢式單例類
在定義靜態變量的時候實例化單例類,在類加載的時候就已經創建了單例對象。在這個類被加載時,靜態變量instance會被初始化,此時類的私有構造函數會被調用,單例類的唯一實例將被創建。
public class EagerSingleton {
private static final EagerSingleton instance = null;
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
懶漢式單例類不是在定義靜態變量時實例化單例類,而是在調用靜態工廠方法時實例化單例類,因此在類加載時並沒有創建單例對象。
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
從資源利用效率角度來說,懶漢式單例類比餓漢式單例類稍好。從速度和反應時間角度來說,餓漢式單例類比懶漢式稍好。然而,懶漢式單例類在實例化時,必須處理好多個線程同時首次引用此類時的訪問限制問題。