首先介紹一下單例模式:?
??? 單例模式(Singleton)捆毫,也叫單子模式,是一種常用的軟件設計模式冲甘。在應用這個模式時,單例對象的類必須保證只有一個實例存在江醇。許多時候整個系統(tǒng)只需要擁有一個的全局對象,這樣有利于我們協(xié)調(diào)系統(tǒng)整體的行為。比如在某個服務器程序中赖晶,該服務器的配置信息存放在一個文件中,這些配置數(shù)據(jù)由一個單例對象統(tǒng)一讀取遏插,然后服務進程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在復雜環(huán)境下的配置管理厂僧。?
實現(xiàn)單例模式的思路是:?
??? 一個類能返回對象一個引用(永遠是同一個)和一個獲得該實例的方法(必須是靜態(tài)方法了牛,通常使用getInstance這個名 稱)颜屠;當我們調(diào)用這個方法時鹰祸,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就創(chuàng)建該類的實例并將實例的引用賦予該類保持的引用粗井;同時我們 還將該類的構(gòu)造函數(shù)定義為私有方法,這樣其他處的代碼就無法通過調(diào)用該類的構(gòu)造函數(shù)來實例化該類的對象浇衬,只有通過該類提供的靜態(tài)方法來得到該類的唯一實例餐济。?
需要注意的地方:?
??? 單例模式在多線程的 應用場合下必須小心使用。如果當唯一實例尚未創(chuàng)建時絮姆,有兩個線程同時調(diào)用創(chuàng)建方法赞赖,那么它們同時沒有檢測到唯一實例的存在冤灾,從而同時各自創(chuàng)建了一個實例, 這樣就有兩個實例被構(gòu)造出來韵吨,從而違反了單例模式中實例唯一的原則。 解決這個問題的辦法是為指示類是否已經(jīng)實例化的變量提供一個互斥鎖(雖然這樣會降低效率)归粉。?
優(yōu)點
(1) 由于單例模式在內(nèi)存中只有一個實例,減少內(nèi)存開支届榄,特別是一個對象需要頻繁地創(chuàng)建銷毀時倔喂,而且創(chuàng)建或銷毀時性能又無法優(yōu)化,單例模式就非常明顯了
(2) 由于單例模式只生成一個實例铝条,所以席噩,減少系統(tǒng)的性能開銷,當一個對象產(chǎn)生需要比較多的資源時埠忘,如讀取配置馒索,產(chǎn)生其他依賴對象時莹妒,則可以通過在應用啟動時直接產(chǎn)生一個單例對象绰上,然后永久駐留內(nèi)存的方式來解決。
(3) 單例模式可以避免對資源的多重占用渔期,例如一個寫文件操作,由于只有一個實例存在內(nèi)存中拘哨,避免對同一個資源文件的同時寫操作
(4) 單例模式可以在系統(tǒng)設置全局的訪問點信峻,優(yōu)化和共享資源訪問倦青,例如盹舞,可以設計一個單例類隘庄,負責所有數(shù)據(jù)表的映射處理癣亚。
缺點
(1)?不適用于變化的對象,如果同一類型的對象總是要在不同的用例場景發(fā)生變化述雾,單例就會引起數(shù)據(jù)的錯誤,不能保存彼此的狀態(tài)唆缴。? ???
(2)?由于單利模式中沒有抽象層,因此單例類的擴展有很大的困難面徽。?
(3)?單例類的職責過重匣掸,在一定程度上違背了“單一職責原則”。?
(4)?濫用單例將帶來一些負面問題旺聚,如為了節(jié)省資源將數(shù)據(jù)庫連接池對象設計為的單例類眶蕉,可能會導致共享連接池對象的程序過多而出現(xiàn)連接池溢出;如果實例化的對象長時間不被利用造挽,系統(tǒng)會認為是垃圾而被回收,這將導致對象狀態(tài)的丟失嵌器。?
使用注意事項:?
(1)?使用時不能用反射模式創(chuàng)建單例,否則會實例化一個新的對象?
(2)?使用懶單例模式時注意線程安全問題?
(3)?餓單例模式和懶單例模式構(gòu)造方法都是私有的爽航,因而是不能被繼承的乾忱,有些單例模式可以被繼承(如登記式模式)?
適用場景:?
??? 單例模式只允許創(chuàng)建一個對象,因此節(jié)省內(nèi)存窄瘟,加快對象訪問速度,因此對象需要被公用的場合適合使用蹄葱,如多個模塊使用同一個數(shù)據(jù)源連接對象等等锄列。如:?
(1)?需要頻繁實例化然后銷毀的對象惯悠。?
(2)?創(chuàng)建對象時耗時過多或者耗資源過多,但又經(jīng)常用到的對象吮螺。?
(3)?有狀態(tài)的工具類對象。?
(4)?頻繁訪問數(shù)據(jù)庫或文件的對象萝风。?
以下都是單例模式的經(jīng)典使用場景:?
(1)?資源共享的情況下紫岩,避免由于資源操作時導致的性能或損耗等规惰。如上述中的日志文件泉蝌,應用配置。?
(2)?控制資源的情況下贪磺,方便資源之間的互相通信。如線程池等寒锚。?
應用場景舉例:?
(1)?外部資源:每臺計算機有若干個打印機违孝,但只能有一個PrinterSpooler,以避免兩個打印作業(yè)同時輸出到打印機雌桑。內(nèi)部資源:大多數(shù)軟件都有一個(或多個)屬性文件存放系統(tǒng)配置,這樣的系統(tǒng)應該有一個對象管理這些屬性文件?
(2)? Windows的Task Manager(任務管理器)就是很典型的單例模式(這個很熟悉吧)拣技,想想看,是不是呢膏斤,你能打開兩個windows task manager嗎制妄? 不信你自己試試看哦~?
(3)?windows的Recycle Bin(回收站)也是典型的單例應用掸绞。在整個系統(tǒng)運行過程中,回收站一直維護著僅有的一個實例烫幕。?
(4)?網(wǎng)站的計數(shù)器敞映,一般也是采用單例模式實現(xiàn),否則難以同步振愿。?
(5)? 應用程序的日志應用,一般都何用單例模式實現(xiàn)冕末,這一般是由于共享的日志文件一直處于打開狀態(tài),因為只能有一個實例去操作枪孩,否則內(nèi)容不好追加。?
(6)?Web應用的配置對象的讀取蔑舞,一般也應用單例模式嘹屯,這個是由于配置文件是共享的資源。?
(7)?數(shù)據(jù)庫連接池的設計一般也是采用單例模式州弟,因為數(shù)據(jù)庫連接是一種數(shù)據(jù)庫資源。數(shù)據(jù)庫軟件系統(tǒng)中使用數(shù)據(jù)庫連接池呆馁,主要是節(jié)省打開或者關(guān)閉數(shù)據(jù)庫連接所引起的效率損耗毁兆,這種效率上的損耗還是非常昂貴的,因為何用單例模式來維護纺腊,就可以大大降低這種損耗茎芭。?
(8)?多線程的線程池的設計一般也是采用單例模式揖膜,這是由于線程池要方便對池中的線程進行控制梅桩。?
(9)?操作系統(tǒng)的文件系統(tǒng),也是大的單例模式實現(xiàn)的具體例子,一個操作系統(tǒng)只能有一個文件系統(tǒng)洪添。?
(10)?HttpApplication 也是單位例的典型應用雀费。熟悉ASP.Net(IIS)的整個請求生命周期的人應該知道HttpApplication也是單例模式,所有的HttpModule都共享一個HttpApplication實例.?