單例模式
單例模式的概念
單例模式指的是只能建立一個實例的類別。單例模式的典型範例包括無狀態物件或唯一的系統元件。但是,單例類別如果沒有將類型定義為介面並以其實作來定義,則難以進行測試。
建立單例模式的方法
使用 public static 且為 final 欄位的成員的方式
private 建構函式僅在初始化 Elvis 實例時呼叫一次,確保整個系統中只有一個實例。但是,可以使用 AccessibleObject.setAccessible() 呼叫 private 建構函式,這種透過反射修改的方法可以在建立第二個物件時丟出例外來阻止。
- 優點
- API 明確顯示該類別為單例。
- 簡潔。
提供 public static 的靜態工廠方法的方式
除了透過反射修改之外,此方法也能確保整個系統中只有一個實例。只是將欄位改為 private,並使用靜態工廠方法來返回物件。
- 優點
- 可以在不更改 API 的情況下,將單例模式改為非單例模式。
- 例如,可以讓靜態工廠方法為每個呼叫它的線程返回不同的實例。
- 如果需要,可以更改為泛型單例工廠方法。
- 可以使用靜態工廠方法的函式參考作為供應商。
- 例如,可以使用 Supplier<Elvis> 代替 Elvis::getInstance。
- 可以在不更改 API 的情況下,將單例模式改為非單例模式。
如果不需要利用上述優點,建議使用第一種方法。
使用列舉類型的方式
最理想的方式是使用列舉類型。與前兩種方法相比,它對反射攻擊更安全,代碼也更簡潔。此外,如下所述,前兩種方法在序列化時需要添加額外的代碼,這是一個缺點。
但是,需要注意的是,雖然要建立的單例可以繼承介面,但不能繼承類別。
序列化單例類別時需要注意的事項
如果要序列化使用第一種或第二種方法建立的單例類別,除了簡單地實現 Serializable 之外,還需要將所有實例欄位宣告為 transient,並重新定義並提供 readResolve() 方法。
评论0