摘要:兩者都基于保持構造函數私有并導出公共靜態成員以提供對唯一實例的訪問。在一種方法中,該成員是字段私有構造器只調用一次,用來初始化靜態變量。由于缺少或者屬性的構造器,這就保證了的全局一致性一旦類被實例化,只會存在一個實例,不多也不少。
??Singleton指僅僅被實例化一次的類 [Gamma95]。Singleton通常代表無狀態的對象,例如函數(第24項)或者本質上唯一的系統組件。使類稱為Singleton會使它的客戶端測試變得十分困難,因為除非它實現了作為其類型的接口,否則不可能將模擬實現替換為單例。
??實現單例的方法有兩種。 兩者都基于保持構造函數私有并導出公共靜態成員以提供對唯一實例的訪問。 在一種方法中,該成員是final字段:
// Singleton with public final field public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTheBuilding() { ... } }
??私有構造器只調用一次,用來初始化靜態變量Elvis.INSTANCE。由于缺少public或者protect屬性的構造器,這就保證了Elvis的全局一致性:一旦Evlis類被實例化,只會存在一個Elvis實例,不多也不少。客戶端所做的任何事情都無法改變這一點,但有一點需要注意:享有特權的客戶端可以借助AccessibleObject.setAccessible方法反射性地調用私有構造函數(第65項)。 如果你需要防御此攻擊,請修改構造函數以使其在要求創建第二個實例時拋出異常。
??在實現Singleton的第二種方法中,公有的成員是個靜態工廠方法:
// 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() { ... } }
??對于靜態方法Elvis.getInstance的所有調用,都會返回同一個對象引用,所以,永遠不會創建其他的Elvis實例(上述提醒依然適用)。
??公有域方法的主要好處在于,組成類的成員的聲明很清楚地聲明了這個類是一個Singleton:公有的靜態域是final的,所以該域總是包含同一個對象的引用。第二個好處就是它更加簡單。
??工廠方法的優勢之一在于,它提供了靈活性:在不改變其API的前提下,我們可以改變類是否應該為Singleton的想法。工廠方法返回唯一實例,但是,它可以很容易被修改,比如改成每個調用該方法的線程返回一個唯一的實例。第二個優點是,如果你的應用需要,你可以編寫泛型單例工廠(第30項)。使用靜態工廠的最后一個優點是方法參考可以用作供應商,例如Elvis::instance是供應商
??為了使利用這其中一種方法實現的Singleton類編程可序列化的(第12章),僅僅在聲明中加上“implements Serializable”是不夠的。為了維護并保證Singleton,必須聲明所有實例域都是瞬時(transient)的,并提供一個readResolve方法(第89項)。否則,每次反序列化時,都會創建一個新的實例,在我們的示例中,會導致“假冒的Elvis”。為了防止這種情況,要在Elvis類中加入下面這個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; }
??實現Singleton還有第三種方法。只需要編寫一個包含單個元素的枚舉類型:
// Enum singleton - the preferred approach public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } }
??這種方法類似于公共領域方法,但它更簡潔,免費提供序列化機制,并提供了對多個實例化的鐵定保證,即使面對復雜的序列化或反射攻擊。這種方法可能會有點不自然,但單元素枚舉類型通常是實現單例的最佳方法。請注意,如果你的單例必須擴展Enum以外的超類,則不能使用此方法(盡管你可以聲明枚舉來實現接口)。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73904.html
摘要:一個類可以提供一個公共靜態工廠方法,它僅僅是一第項遇到多個構造器參數時要考慮使用構建器靜態工廠和構造器有個共同的局限性他們都不能很好地擴展到大量的可選參數。 ??本章涉及創建和銷毀對象,包括何時以及如何創建它們,何時以及如何避免創建它們,如何確保它們被及時銷毀,以及如何管理在銷毀之前必須進行的清理操作。 第1項:用靜態工廠方法代替構造器 ??類允許客戶端獲取實例的傳統方法是提供公共構造...
摘要:推薦序前言致謝第一章引言第二章創建和銷毀對象第項用靜態工廠方法代替構造器第項遇到多個構造器參數時要考慮使用構建器第項用私有構造器或者枚舉類型強化屬性第項通過私有構造器強化不可實例化的能力第項優先考慮依賴注入來引用資源第項避免創建不必要的對象 推薦序 前言 致謝 第一章 引言 第二章 創建和銷毀對象 第1項:用靜態工廠方法代替構造器 第2項:遇到多個構造器參數時要考慮使用構建器 第...
摘要:本章中的大部分內容適用于構造函數和方法。第項其他方法優先于序列化第項謹慎地實現接口第項考慮使用自定義的序列化形式第項保護性地編寫方法第項對于實例控制,枚舉類型優先于第項考慮用序列化代理代替序列化實例附錄與第版中項目的對應關系參考文獻 effective-java-third-edition 介紹 Effective Java 第三版全文翻譯,純屬個人業余翻譯,不合理的地方,望指正,感激...
摘要:第二章創建和銷毀對象何時以及如何創建對象,何時以及如何避免創建對象,如何確保他們能夠適時地銷毀,以及如何管理對象銷毀之前必須進行的各種清理動作。表示工廠方法所返回的對象類型。 第二章 創建和銷毀對象 何時以及如何創建對象,何時以及如何避免創建對象,如何確保他們能夠適時地銷毀,以及如何管理對象銷毀之前必須進行的各種清理動作。 1 考慮用靜態工廠方法代替構造器 一般在某處獲取一個類的實例最...
閱讀 2299·2021-11-24 09:38
閱讀 2124·2021-11-22 14:44
閱讀 1157·2021-07-29 13:48
閱讀 2622·2019-08-29 13:20
閱讀 1120·2019-08-29 11:08
閱讀 2061·2019-08-26 10:58
閱讀 1267·2019-08-26 10:55
閱讀 3163·2019-08-26 10:39