單例模式(Singleon Patttern)是一個比較簡單的模式,其定義如下:
Ensure a class has only one instance,and provide a global point of access to it.
確保一個類只有一個實例,并且提供一個方法來得到這個實例。
1. 餓漢式
package 單例模式;
public class EagerSingleton {
private static final EagerSingleton instance= new EagerSingleton();
private EagerSingleton(){}
//靜態工廠方法
public static EagerSingleton getInstance(){
return instance;
}
}
當EagerSingleton 類被加載的時候,靜態變量instance被初始化。
2. 懶漢式
package 單例模式;
public class LazySingleton {
private static LazySingleton instance =null;
private LazySingleton(){}
synchronized public static LazySingleton getInstance(){
if(instance==null){
instance=new LazySingleton();
}
return instance;
}
}
懶漢式中的getInstance()
方法使用了同步化,防止在多線程環境下出現多個實例。
不過,值得注意的是,單例模式并不能保證在所有的情況下都能實現單例,例如在多個虛擬機或多個類加載器的情況下,有可能會產生多于一個的實例,具體的情況可以參考這里,如果不想看英文,有中文的翻譯。
- 使用enum關鍵字
public enum Singleton {
INSTANCE;// 唯一實例
public void print() {
System.out.println("使用enum實現單例模式");
}
// public static Singleton getInstance() {
// return INSTANCE;
// }
public static void main(String[] args) {
// Singleton sole=Singleton.getInstance();
Singleton sole = Singleton.INSTANCE;
sole.print();
}
}
http://blog.sina.com.cn/s/blog_3fe961ae0100ouwg.html
這其實是一種比較trick的方法,在《Effictive Java》一書中作者強烈推薦。這么多年來,其實很少使用enum來實現單例模式,雖然它有很多優點,但也有缺點。比如不可以繼承類,不可以實現接口,這種寫法對于一些研發人員來說也比較陌生,會多一些心智負擔,用得更多的反而是懶漢式。另外使用單例模式多了,也發現單例模式存在的一些問題:
第一,由于單例模式中沒有抽象層,因此單例類的擴展有很大的困難。另外類的構造函數通常也是私有的,所以無法被繼承。尤其在單元測試的時候,我們常常需要繼承原始的類,并覆寫一些方法以達到mock的目的。
第二,對需要多例的集成測試不友好。雖然類A在正常情況下,一個進程中只應該有一個實例,但是在集成測試的時候,我們可能需要在同一個進程里構造出兩個A的實例,以方便測試。
第三,代碼模塊之間的依賴不清晰。舉例,當模塊B需要使用類A的實例,它通常可以A.getInstance()來獲取A的唯一實例,這樣會造成整個項目代碼中,到處都有A.getInstance()這樣的使用,于是很難看出到底哪些模塊真正依賴A。而如果B的構造函數是B(A a),那么就可以很直觀地看出B對A的依賴。