我眼中的單例模式


說到單例模式,網上搜索出來的結果是多如牛毛,但這不影響我也來湊熱鬧的心情。

任何事情都是要親身去體會了,才能加深自己的理解。本着不斷學習進取的精神,我很想可以站在牛人的肩膀上,哪怕是仰視牛人的情況下,我也想發揮自己的余熱。記錄下自己學習的足跡,權當自己未來細細回味也好。(不過說真的,自己試着去組織語言來介紹你的問題也好,你的產品也好,能在很大的程度上提高你的表達能力。大腦是越鍛煉越活的東西,講話、寫作也一樣,持之以恆,必有收獲。總之,貴在堅持哦!)

好了,我先聲明下我參考的牛人文章出處: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實例。

當然如果你有新的使用場景,請不吝賜教:)

至此,本文完!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM