說到單例模式,網上搜索出來的結果是多如牛毛,但這不影響我也來湊熱鬧的心情。
任何事情都是要親身去體會了,才能加深自己的理解。本着不斷學習進取的精神,我很想可以站在牛人的肩膀上,哪怕是仰視牛人的情況下,我也想發揮自己的余熱。記錄下自己學習的足跡,權當自己未來細細回味也好。(不過說真的,自己試着去組織語言來介紹你的問題也好,你的產品也好,能在很大的程度上提高你的表達能力。大腦是越鍛煉越活的東西,講話、寫作也一樣,持之以恆,必有收獲。總之,貴在堅持哦!)
好了,我先聲明下我參考的牛人文章出處:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html
下面來介紹模式,單例模式就是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
其實就是實現只有一個門可以進入,且每次只給一個人進入。這就像以前的一位博友所舉的例子,很多人排隊去廁所蹲坑一樣,每一次只能讓一個人去蹲坑。實現單例模式的原因,要么是資源共享,要么是控制資源等。所謂資源共享,就是因為單例模式保證了一個類僅有一個實例,所以大家訪問的實例是一致的。而控制資源的話,主要是減少資源的申請與釋放等。
牛人就是牛人,一下給出了五種實現單例模式的例子。看得我茅塞頓開,大呼過癮。
第一種:簡單實現(惰性實例化) |
namespace Singleton { public class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); } } public sealed class Singleton { private Singleton() { } private static Singleton instance = null; public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } } }
簡單實現對於線程來說是不安全的,因為在多線程的情況下,有可能產生多個Singleton實例。多線程的情況下,如果多個線程都去判斷(instance == null),而它們都還沒有創建實例的情況下,就會產生多個Singleton實例。對於簡單實現來講,Singleton實例化並不是應用程序啟動就創建,所以我們把它叫做“惰性實例化”,這能避免應用程序啟動時實例化不必要的實例。
第二種:安全的線程 |
namespace Singleton { public class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); } } public sealed class Singleton { private Singleton() { } private static Singleton instance = null; private static readonly object padLock = new object(); public static Singleton Instance { get { lock (padLock) { if (instance == null) { instance = new Singleton(); } return instance; } } } } }
安全的線程,這是對簡單實例的補充。因為提供了加鎖lock()的操作,這就能確保只有一個線程進入。但是加鎖需要增加額外的開銷,損失性能。
第三種:雙重鎖定檢查 |
namespace Singleton { public class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); } } public sealed class Singleton { public Singleton() { } private static Singleton instance = null;
private static readonly object padLock = new object(); public static Singleton Instance { get { if (instance == null) { lock (padLock) { if (instance == null) { instance = new Singleton(); } } } return instance; } } } }
雙重鎖定檢查在安全的線程上面又進行了改進,主要是考慮了每次加鎖會增加額外的開銷,影響性能。所以在加鎖前再判斷Singleton有沒有被實例化。這樣,它就能減少很多的額外開銷且是線程安全的。實際上,應用程序很少需要上面方式的實現。這種方式仍然有很多缺點:無法實現延遲初始化。大多數情況下我們會使用靜態初始化的方式。
第四種:靜態初始化 |
namespace Singleton { public class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); } } public sealed class Singleton { static readonly Singleton instance = new Singleton(); private Singleton() { } public static Singleton Instance { get { return instance; } } } }
靜態初始化,是在 .NET 中實現 Singleton 的首選方法。 這段代碼有點意思,我也解讀一下。主要是講解下關鍵字吧。
sealed:修改類,意為這個類不可再被繼承,防止子類被實例化而不能保證只有一個實例的問題。
private Singleton():用private 修改構造函數,可以防止這個類在外部被實例。也就是在Singleton類外面想new Singleton()是會報編譯錯誤。
static readonly:表示只能在聲明時賦值,或是在靜態構造中賦值。
第五種:延遲初始化 |
namespace Singleton { class Program { static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } Console.Read(); } } public sealed class Singleton { public Singleton() { } public static Singleton Instance { get { return Delay.DelayInstance; } } } public sealed class Delay { private static readonly Singleton delayInstance = new Singleton(); private Delay() { } public static Singleton DelayInstance { get { return delayInstance; } } } }
把實例化的工作交給Delay類開實現,這樣Singleton類就實現了延遲初始化。這種方式具有很多的優勢,是值得推薦的一種實現方式。但是這種方式就需要開發人員記住不能使用new關鍵字實例化Singleton。
應用場景 |
其實不管是對於哪個設計模式來說,我們總會想知道什么時候能用到它。畢竟東西不是白學的,是貓是狗總也得帶出來溜溜。
畢竟我也使用得少,所以這里面為了讓網友能夠看得大而全點,我摘自博友的內容如下:
1. Windows的Task Manager(任務管理器)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能打開兩個windows task manager嗎? 不信你自己試試看哦~
2. windows的Recycle Bin(回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護着僅有的一個實例。
3. 網站的計數器,一般也是采用單例模式實現,否則難以同步。
4. 應用程序的日志應用,一般都可用單例模式實現,這一般是由於共享的日志文件一直處於打開狀態,因為只能有一個實例去操作,否則內容不好追加。
5. Web應用的配置對象的讀取,一般也應用單例模式,這個是由於配置文件是共享的資源。
6. 數據庫連接池的設計一般也是采用單例模式,因為數據庫連接是一種數據庫資源。數據庫軟件系統中使用數據庫連接池,主要是節省打開或者關閉數據庫連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因為使用單例模式來維護,就可以大大降低這種損耗。
7. 多線程的線程池的設計一般也是采用單例模式,這是由於線程池要方便對池中的線程進行控制。
8. 操作系統的文件系統,也是單例模式實現的具體例子,一個操作系統只能有一個文件系統。
9. HttpApplication 也是單例模式的典型應用。熟悉ASP.Net(IIS)的整個請求生命周期的人應該知道HttpApplication也是單例模式,所有的HttpModule都共享一個HttpApplication實例。
當然如果你有新的使用場景,請不吝賜教:)
至此,本文完!