2024-10-22
基本概念
Singleton 是一種創(chuàng)立性模型,它用來確保只發(fā)生一個(gè)實(shí)例,并供給一個(gè)訪問它的大局訪問點(diǎn).對一些類來說,確保只要一個(gè)實(shí)例是很重要的,比方有的時(shí)候,數(shù)據(jù)庫銜接或 Socket 銜接要遭到一定的約束,必須保持同一時(shí)間只能有一個(gè)銜接的存在.再舉個(gè)比如,調(diào)集中的 set 中不能包含重復(fù)的元素,添加到set里的目標(biāo)必須是僅有的,假如重復(fù)的值添加到 set,它只承受一個(gè)實(shí)例.JDK中正式運(yùn)用了Singleton形式來完成 set 的這一特性,我們能夠檢查java.util.Collections里的內(nèi)部靜態(tài)類SingletonSet的原代碼.其實(shí)Singleton是簡單但也是應(yīng)用廣泛的形式之一,在 JDK 中隨處可見.
簡單分析
為了完成 Singleton 形式,咱們需要的是一個(gè)靜態(tài)的變量,能夠在不創(chuàng)立目標(biāo)的情況下回憶是否現(xiàn)已發(fā)生過實(shí)例了.靜態(tài)變量或靜態(tài)方法都能夠在不發(fā)生詳細(xì)實(shí)例的情況下直接調(diào)用,這樣的變量或方法不會由于類的實(shí)例化而有所改動.在圖1的結(jié)構(gòu)中能夠看到,uniqueInstance 便是這個(gè)獨(dú)立的靜態(tài)變量,它能夠回憶目標(biāo)是否現(xiàn)已實(shí)例化了,在靜態(tài)方法 Instance 中對這個(gè)變量進(jìn)行判別,若沒有實(shí)例化過就發(fā)生一個(gè)新的目標(biāo),假如現(xiàn)已實(shí)例化了則不再發(fā)生新的目標(biāo),仍然返回曾經(jīng)發(fā)生的實(shí)例.
詳細(xì)施行
完成 Singleton 形式的方法通常有三種.
一. 用靜態(tài)方法完成 Singleton 這種方法是使用靜態(tài)方法來監(jiān)督實(shí)例的創(chuàng)立.為了避免創(chuàng)立一個(gè)以上的實(shí)例,咱們好把結(jié)構(gòu)器聲明為 private.
這樣能夠避免客戶程序員經(jīng)過除由咱們供給的方法之外的恣意方法來創(chuàng)立一個(gè)實(shí)例,假如不把結(jié)構(gòu)器聲明為private,編譯器就會自作聰明的自動同步一個(gè)默認(rèn)的friendly結(jié)構(gòu)器.這種完成方法是常見的,也便是圖1中結(jié)構(gòu)的規(guī)范完成.
singletonTest運(yùn)行結(jié)果是:
Creating one instance
Creating two instance
Only one instance allowed
能夠看出,第一個(gè)實(shí)例順利創(chuàng)立,第二個(gè)實(shí)例創(chuàng)立實(shí)拋出了咱們自定義的異常.
三. 用注冊器機(jī)制來創(chuàng)立 Singleton 首先用調(diào)集中的Hashtable 和Enumeration來完成addItem(Object key, Object value),getItem(Object key), ,removeItem(Object key)等方法完成一個(gè)辦理器,將key和value逐個(gè)關(guān)聯(lián)起來,客戶程序員創(chuàng)立實(shí)例前首先用addItem方法進(jìn)行注冊,再用getItem方法獲取實(shí)例.Hashtable中的key是僅有的,從而確保創(chuàng)立的實(shí)例是僅有的,詳細(xì)完成限于篇幅不再細(xì)說,在Prototype模型的應(yīng)用一文中我將會給出一個(gè)完成注冊器的代碼.用注冊器機(jī)制來創(chuàng)立 Singleton形式的優(yōu)點(diǎn)是易于辦理,能夠同時(shí)控制多個(gè)不同類型的Singleton 實(shí)例.
小結(jié)
Singleton形式能夠方便的進(jìn)行擴(kuò)充,發(fā)生指定數(shù)目的實(shí)例.
在The Design Patterns Java Companion 一書中曾提到過用靜態(tài)類的方法來完成 Singleton形式,并指出java.lang.Math便是一個(gè)比如,這兒我并不表明贊同,由于Math并不是一個(gè)真正的目標(biāo),咱們僅僅直接調(diào)用Math類所包裝的靜態(tài)方法而已,根本就沒有創(chuàng)立實(shí)例的過程,又從何說起只發(fā)生一個(gè)實(shí)例呢?這個(gè)問題我曾到Javaranch的論壇上發(fā)過帖子,所有回帖的人也都是對這一觀點(diǎn)持否定態(tài)度.
在多線程的程序中,singleton可能會變的不可靠,可能會出現(xiàn)多個(gè)實(shí)例,解決的方法很簡單,加個(gè)同步修飾符: public static synchronized Singleton getInstance(). 這樣就確保了線程的安全性.
后要說的是我們可能會看見一些其他完成Singleton形式的方法,由于形式在詳細(xì)的應(yīng)用時(shí)是靈活的,不是一成不變的,并沒有一個(gè)固定的做法,但大都是上面幾種方法的變形.但也要注意單例模式可能會帶來一些問題,如測試?yán)щy、可能會隱藏不良的設(shè)計(jì)等,在使用時(shí)需要根據(jù)具體情況進(jìn)行權(quán)衡。