[英]Singleton Pattern
像我之前的問題一樣,這個問題引用了Effective Java 。 這次我有很多子問題。
特權客戶端可以借助AccessibleObject.setAccessible()
方法反射性地調用私有構造函數。 如果您需要防范此操作,請修改構造函數。
究竟如何調用私有構造函數? 什么是AccessibleObject.setAccessible()
?
您的專家對單身人士采用什么方法?
// Approach A public class Test{ public static final Test TestInstance = new Test(); private Test(){ ... } . . . } // Approach B public class Test{ private static final Test TestInstance = new Test(); private Test(){ ... } public static Test getInstance() { return TestInstance; } . . . }
第二種方法是不是更靈活,以防我們每次都要檢查新實例或每次檢查同一個實例?
如果我嘗試克隆類/對象怎么辦?
單元素枚舉類型是實現單例的最佳方式。
為什么? 怎么樣?
特權限制的cleint可以借助AccessibleObject.setAccessible方法反射性地調用私有構造函數。如果需要保護它,請修改構造函數。 我的問題是:如何調用私有構造函數? 什么是AccessibleObject.setAccessible?
顯然,類本身可以調用私有構造函數(例如,從靜態工廠方法)。 反過來,布洛赫正在談論的是:
import java.lang.reflect.Constructor;
public class PrivateInvoker {
public static void main(String[] args) throws Exception{
//compile error
// Private p = new Private();
//works fine
Constructor<?> con = Private.class.getDeclaredConstructors()[0];
con.setAccessible(true);
Private p = (Private) con.newInstance();
}
}
class Private {
private Private() {
System.out.println("Hello!");
}
}
2.專家對單身人士采取什么方法:
...
通常,第一個是受歡迎的。
第二個(假設您在返回新實例之前測試
TestInstance
是否為null)以需要同步或線程不安全為代價獲得延遲加載。
當你的第二個例子沒有在聲明時將實例分配給TestInstance
時,我寫了上面的內容。 如上所述,上述考慮無關緊要。
第二種方法是不是更靈活,以防我們每次都要檢查新實例或每次都是同一個實例?
它不是關於靈活性,而是關於何時產生創建一個(且唯一的)實例的成本。
如果你選擇a)它是在課堂加載時產生的。
這通常很好,因為只有在需要時才會加載類。
當你的第二個例子沒有在聲明時將實例分配給TestInstance
時,我寫了上面的內容。 如前所述,在兩種情況下,Singleton都將在類加載時創建。
如果我嘗試克隆類/對象怎么辦?
單身人士不應該出於明顯的原因而允許克隆。 應拋出CloneNotSupportedException,除非由於某種原因實現Cloneable
否則將自動拋出。
單元素枚舉類型是實現單例的最佳方式。 為什么? 如何?
這方面的例子在書中,正如理由一樣。 你不懂什么部分?
特權限制的cleint可以借助AccessibleObject.setAccessible方法反射性地調用私有構造函數。如果需要保護它,請修改構造函數。 我的問題是:如何調用私有構造函數? 什么是AccessibleObject.setAccessible?
您可以使用java反射來調用私有構造函數。
您的專家對單身人士采用什么方法:
我是使用枚舉來實際執行此操作的粉絲。 這也在書中。 如果這不是一個選項,那么選擇a更簡單,因為您不必檢查或擔心已經創建了實例。
如果我嘗試克隆類/對象怎么辦?
不明白你的意思? 你的意思是克隆()或其他我不知道的東西?
單元素枚舉類型是實現單例的最佳方式。 為什么? 如何?
啊,我自己的答案。 哈哈。 這是最好的方法,因為在這種情況下,java編程語言保證單例而不是開發人員必須檢查單例。 這幾乎就像單身人士是框架/語言的一部分。
編輯:我之前沒有看到它是一個吸氣劑。 更新我對此的回答 - 最好使用getInstance這樣的函數,因為你可以控制通過getter發生的事情,但如果每個人都直接使用引用,你就不能這樣做。 想想未來。 如果你最終做了SomeClass.INTANCE,然后你想讓它變得懶惰,所以它不會立即加載,那么你需要在它被使用的任何地方進行更改。
單身人士是一個很好的學習模式,尤其是作為入門設計模式。 但要注意,它們通常最終成為最常用的模式之一 。 有人認為它們是一種“反模式” 。 最好的建議是“明智地使用它們”。
有關這方面的很好的介紹,以及許多其他有用的模式(我個人認為策略,觀察者和命令比Singleton更有用),請查看Head First Design Patterns 。
Singleton(反)模式的第一條規則是不使用它 。 第二個規則是不要使用它 ,以便更容易獲得您希望多個其他對象共享的類的單個實例, 特別是如果它是這些類的依賴項。 改為使用依賴注入。 單身人士有一些有效的用途,但是人們會嚴重濫用他們,因為他們使用起來非常“容易”。 他們很難測試依賴於它們的類並使系統不靈活。
至於你的問題,我認為1,2和3都可以說“使用回答enum
-singleton”。 然后你不必擔心構造函數accessiblity問題, clone()
ing等。至於4 ,上面的內容對他們來說是一個很好的論據。 我還要問一下,您是否閱讀過有效Java中明確回答您問題的部分?
示例singleton lazy init:類main:
public class Main {
public static void main(String[] args) {
System.out.println(Singleton.getInstance("first").value);
System.out.println(Singleton.getInstance("second").value);
System.out.println(Singleton.getInstance("therd").value);
}
}
班級單身人士:
public class Singleton {
private static Singleton instance;
public String value;
private Singleton (String s){
this.value =s;
}
public static Singleton getInstance(String param) {
if (instance == null)
instance = new Singleton(param);
return instance;
}
}
啟動應用程序時,控制台將包含下一個字符串
first
first
first
\\ | / 73
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.