單件模式是一種用于確保整個應(yīng)用程序中只有一個類實例且這個實例所占資源在整個應(yīng)用程序中是共享時的程序設(shè)計方法(根據(jù)實際情況,可能需要幾個類實例)。在某些情況下,這種程序設(shè)計方法是很有用處的。

設(shè)計模式-單件模式(singleton)

單件模式應(yīng)該使用在什么場合

當(dāng)需要控制一個類的實例數(shù)量且調(diào)用者可以從一個公共的訪問點訪問時。

單件模式類的創(chuàng)建

我們分兩種方式來討論一個單件類的創(chuàng)建,一是將一個類的公共構(gòu)造函數(shù)改為私有,另一種方式是保留類的公共構(gòu)造函數(shù),通過一個靜態(tài)成員來決定是否要返回一個類實例。

Singleton模式

Singleton可以說是《Design Pattern》中最簡單也最實用的一個設(shè)計模式。那么,什么是Singleton?

顧名思義,Singleton就是確保一個類只有唯一的一個實例。Singleton主要用于對象的創(chuàng)建,這意味著,如果某個類采用了Singleton模式,則在這個類被創(chuàng)建后,它將有且僅有一個實例可供訪問。很多時候我們都會需要Singleton模式,最常見的比如我們希望整個應(yīng)用程序中只有一個連接數(shù)據(jù)庫的Connection實例;又比如要求一個應(yīng)用程序中只存在某個用戶數(shù)據(jù)結(jié)構(gòu)的唯一實例。我們都可以通過應(yīng)用Singleton模式達(dá)到目的。

一眼看去,Singleton似乎有些像全局對象。但是實際上,并不能用全局對象代替Singleton模式,這是因為:其一,大量使用全局對象會使得程序質(zhì)量降低,而且有些編程語言例如C#,根本就不支持全局變量。其二,全局對象的方法并不能阻止人們將一個類實例化多次:除了類的全局實例外,開發(fā)人員仍然可以通過類的構(gòu)造函數(shù)創(chuàng)建類的多個局部實例。而Singleton模式則通過從根本上控制類的創(chuàng)建,將"保證只有一個實例"這個任務(wù)交給了類本身,開發(fā)人員不可能再有其它途徑得到類的多個實例。這一點是全局對象方法與Singleton模式的根本區(qū)別。

Singleton模式的實現(xiàn)Singleton模式的實現(xiàn)基于兩個要點:1)不直接用類的構(gòu)造函數(shù),而另外提供一個Public的靜態(tài)方法來構(gòu)造類的實例。通常這個方法取名為Instance。Public保證了它的全局可見性,靜態(tài)方法保證了不會創(chuàng)建出多余的實例。2)將類的構(gòu)造函數(shù)設(shè)為Private,即將構(gòu)造函數(shù)"隱藏"起來,任何企圖使用構(gòu)造函數(shù)創(chuàng)建實例的方法都將報錯。這樣就阻止了開發(fā)人員繞過上面的Instance方法直接創(chuàng)建類的實例。通過以上兩點就可以完全控制類的創(chuàng)建:無論有多少地方需要用到這個類,它們訪問的都是類的唯一生成的那個實例。以下C#代碼展現(xiàn)了兩種實現(xiàn)Singleton模式的方式,開發(fā)人員可以根據(jù)喜好任選其一。實現(xiàn)方式一:Singleton.csusing System;class SingletonDemo{ private static SingletonDemo theSingleton = null;private SingletonDemo() {}public static SingletonDemo Instance(){ if (null == theSingleton){theSingleton = new SingletonDemo();}return theSingleton;}static void Main(string[] args){ SingletonDemo s1 = SingletonDemo.Instance();SingletonDemo s2 = SingletonDemo.Instance();if (s1.Equals(s2)){ Console.WriteLine("see, only one instance!");}}}與之等價的另外一種實現(xiàn)方式是:Singleton.cs:using System;class SingletonDemo{ private static SingletonDemo theSingleton = new SingletonDemo();private SingletonDemo() {}public static SingletonDemo Instance(){ return theSingleton;}static void Main(string[] args){ SingletonDemo s1 = SingletonDemo.Instance();SingletonDemo s2 = SingletonDemo.Instance();if (s1.Equals(s2)){ Console.WriteLine("see, only one instance!");}}}編譯執(zhí)行:Csc Singleton.cs得到運(yùn)行結(jié)果:see, only one instance!.NET中的Singleton因為Singleton模式具有這樣實用的價值,開發(fā)人員除了可以在程序代碼中直接使用Singleton模式外,在許多大型系統(tǒng)的實現(xiàn)上也都處處可見它的影子。在微軟隆重推出的.NET框架中,同樣也可以發(fā)現(xiàn)Singleton思想閃爍的光芒。舉例來說,在.NET框架的重要組成部分Remoting中,遠(yuǎn)程對象(Remote Object)有兩種激活方式:服務(wù)器端激活方式和客戶端激活方式。采用服務(wù)器端激活方式的對象又分為兩種類型:Singleton對象和SingleCall對象。Singleton 對象是這樣的對象:無論該對象有多少個客戶端調(diào)用,它總是只有一個實例,由這個實例來處理所有的客戶端請求。相反地,若將遠(yuǎn)程對象聲明為 SingleCall,則系統(tǒng)會為每次客戶端方法的調(diào)用創(chuàng)建一個新對象,即使這些方法調(diào)用來自同一個客戶端,也即,對象只在方法調(diào)用持續(xù)期間存在,一旦方法調(diào)用結(jié)束,該對象就會被銷毀。顯而易見,這里的Singleton對象就是設(shè)計模式Singleton思想在.NET中的應(yīng)用。那么,如何在.NET的Remoting中利用Singleton?.NET提供了兩種方式將一個遠(yuǎn)程對象注冊為Singleton:直接調(diào)用RegisterWellKnownServiceType方法,在參數(shù)中指定對象類型為Singleton;或在配置文件web.config中設(shè)定遠(yuǎn)程對象的類型為Singleton。這兩種方法的效果相同,所不同的是后一種方法顯得更加方便,因為改變配置文件的內(nèi)容后,不必重新編譯應(yīng)用程序。下列代碼顯示了如何使用RegisterWellKnownServiceType方法注冊遠(yuǎn)程對象類型:RemotingConfiguration.RegisterWellKnownServiceType( Type.GetType("RemotingSamples.HelloServer,object"), "SayHello", WellKnownObjectMode.Singleton);參數(shù)"SayHello"是客戶端訪問遠(yuǎn)程對象(這里是HelloServer)時用來代表遠(yuǎn)程對象的URI,例如tcp://localhost:8085/SayHello(假設(shè)使用的是TCP通道)。最后一個參數(shù)就指明了這個遠(yuǎn)程對象是Singleton類型。一旦將遠(yuǎn)程對象注冊為Singleton,則在第一次客戶端調(diào)用HelloServer的方法時創(chuàng)建這個遠(yuǎn)程對象,然后保持它直到客戶端中斷連接或?qū)ο蟪瑫r被銷毀為止。在此期間,無論有多少個客戶端調(diào)用這個遠(yuǎn)處對象,所有的客戶請求都將由那個已經(jīng)存在的唯一實例接受處理。這就是Singleton在.NET中的應(yīng)用。從Singleton模式的實現(xiàn)和應(yīng)用中也可以看出,優(yōu)秀的設(shè)計模式往往都具有"簡約之美"。它們采用一種"優(yōu)雅"的方式,將那些成功的設(shè)計方法和體系結(jié)構(gòu)能夠得以被簡單、方便地復(fù)用。這也是為什么現(xiàn)在的軟件開發(fā)日益強(qiáng)調(diào)"設(shè)計模式"的原因之所在。如果想進(jìn)一步了解更多的設(shè)計模式,還是推薦各位閱讀Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides的經(jīng)典之作《Design Pattern》