Effective.Java 讀書筆記(3)關於單例模式

3.Enforce the singleton property with a private constructor or an enum type
大意爲 使用parivate的構造方法或者一個枚舉的類型實現單例屬性

一個單例即使一個類只初始化一次來簡化這個類

特別地,單例代表一個內在獨立的系統組件,比如窗口管理或者文件系統

使一個類成爲單例這件事會使得難以測試它的用戶,正如對於使用一個單例代替一個模擬實現除非它實現了一個接口,而這個接口作爲它的類型的事是不可能的

release 1.5之前有着兩種方法來實現單例,都是基於使構造方法private然後導入一個public的靜態成員來提供唯一的實例,其中一種方法中,成員是一個final域

// Singleton with public final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
}

private的構造方法只調用一次,用來初始化public的靜態final域中的Elivis.INSTANCE,一個public或者protected的構造方法的缺失保證了一個單例的存在,書中稱爲(”monoelvistic“ universe)

的確這樣只有一個實例存在,用戶不能改變它只有一個的事實,不管通過什麼手段,需要注意的是,一個優先級別的用戶可以通過使用AccessibleObject.setAccessible的幫助來重新調用private的構造方法,如果你需要預防這件事的發生,你可以定義構造方法當創建第二個實例的時候直接拋出一個異常

第二個方法來實現單例,即public的成員事一個靜態工廠方法

// Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public void leaveTheBuilding() { ... }
}

每次調用getInstance方法都會返回相同的一個對象的引用,並且沒有其他實例會曾經被創建,和第一個方法一樣需要預防強制調用

第一個方法的主要優點在於聲明使這個類是單例這件事更加清晰,不再有其他的優點了,如今的JVM的實現大多數都是用使用靜態工廠方法

使用第二個方法的優點在於給你更加強大的靈活性,你可以改變單例的模式而不需要更改API,工廠方法返回唯一實例但是可以簡單改爲返回實例,這樣說,相應的被調用的線程的一個特殊的實例。

第二個優點是,關注通用類型,後面可能會說到,這些優點都不相關,只能說第一個方法更加簡單。

爲了使單例的類可以使用其他的以前的方法(Serializable可序列化)來實現,僅僅加上可序列化的實現並不足夠,爲了保持單例,你必須短暫聲明所有的實例域並且提供readResolve方法(之後會提及),否則每次一個序列化了的實例都反序了

// readResolve method to preserve singleton property
private Object readResolve() {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator(模仿者).
return INSTANCE;
}

1.5之後,有第三種方法實現單例,簡單創建一個含一個元素的枚舉類

public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

這種方法和第一種方法功能上是相等的,相較之下更加地簡潔明瞭,提供序列化功能並且提供穩固的保證來對抗多次實例的危險,甚至面對複雜的序列或者反覆攻擊的時候也可以提供安全保證,這種方法已經廣泛被推廣了,一個單一元素的枚舉類型是實現單例的最好方式

發佈了45 篇原創文章 · 獲贊 12 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章