單例模式 - OK

  單例模式(Singleton):保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。javascript

1、單例模式

  一般咱們可讓一個全局變量使得一個對象被訪問,但它不能防止你實例化多個對象。一個最好的辦法就是,讓類自身負責保存它的惟一實例。這個類能夠保證沒有其餘實例能夠被建立,而且它能夠提供一個訪問該實例的方法。java

  單例模式結構圖:安全

  

  Singleton類,定義一個GetInstance操做,容許客戶訪問它的惟一實例。GetInstance是一個靜態方法,主要負責建立本身的惟一實例。多線程

  單例模式示例:函數

複製代碼
namespace ConsoleApplication1
{
    public class Singleton
    {
        private static Singleton instance;

        private Singleton()     //將構造方法設爲private,防止外界利用new建立實例。
        { 
            
        }

        public static Singleton GetInstance()   //此方法用於得到本類實例的惟一全局訪問點
        {
            if (instance == null)           //若實例不存在則new一個新實例,不然返回已有實例
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Singleton singleton1 = Singleton.GetInstance();
            Singleton singleton2 = Singleton.GetInstance();       //調用靜態方法得到實例
            if (singleton1 == singleton2)
            {
                Console.WriteLine("兩個對象是相同的實例!");       //輸出 兩個對象是相同的示例
            }
            Console.ReadKey();
        }
    }  
}
複製代碼

  單例模式與實用類(靜態方法)的不一樣點:post

    一、實用類不保存狀態,僅提供一些靜態方法或靜態屬性讓你用,而單例是由狀態的。this

    二、實用類不能用於繼承多態,而單例雖然實例惟一,倒是能夠有子類來繼承。spa

    三、實用類只不過是一些方法屬性的集合,而單例倒是有着惟一的對象實例。線程

2、多線程時的單例

  在上面的例子中,若是是在多線程的程序中,多個線程同時(注意是同時)訪問Singleton類,調用GetInstance()方法,會有可能形成建立多個實例的。所以能夠經過加lock來處理,lock是確保當一個線程位於代碼的臨界區,另外一個線程不進入臨界區。若是其餘線程視圖進入鎖定的代碼,則它將一直等待(即被阻止),直到對象被釋放。code

  雙重鎖定代碼示例:

複製代碼
namespace ConsoleApplication1
{
    public class Singleton
    {
        private static Singleton instance;
        private static readonly object syncRoot = new object();

        private Singleton()     //將構造方法設爲private,防止外界利用new建立實例。
        { 
            
        }

        public static Singleton GetInstance()   //此方法用於得到本類實例的惟一全局訪問點
        {
            if (instance == null)           //若是實例爲空,在外面作一層判斷的做用是,當實例不爲null時,不用lock,減小資源消耗。
            {   
                lock (syncRoot)             //鎖定
                {
                    if (instance == null)   //當兩個線程同時調用GetInstance()時,他們均可以經過第一重instance=null的判斷,而後因爲lock機制,
                    //這兩個線程只有一個進入,另外一個等候,若是沒有第二重的instance=null的判斷,則第一個線程建立了實例,第二個線程因爲過了第一重instance=null,
                    //所以在沒有第二重instance == null判斷的狀況下仍是會建立實例。
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Singleton singleton1 = Singleton.GetInstance();
            Singleton singleton2 = Singleton.GetInstance();       //調用靜態方法得到實例
            if (singleton1 == singleton2)
            {
                Console.WriteLine("兩個對象是相同的實例!");       //輸出 兩個對象是相同的示例
            }
            Console.ReadKey();
        }
    }  
}
複製代碼

3、靜態初始化

  其實在實際應用中,C#與公共語言運行庫也提供了一種‘靜態初始化’方法,這種方法不須要開發人員顯式地編寫線程安全代碼,既可解決多線程環境下它是不安全的問題。相對於上面的來講,兩種方法均可以達到相同的單例目的,只是實現更加簡單而已,來看下實現代碼:

複製代碼
namespace ConsoleApplication1
{
    public sealed class Singleton   //注意必須設置爲密封類
    {
        private static readonly Singleton instance = new Singleton();    //注意聲明爲只讀
        private Singleton() 
        {

        }
        public static Singleton GetInstance()
        {
            return instance;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Singleton singleton1 = Singleton.GetInstance();
            Singleton singleton2 = Singleton.GetInstance();       //調用靜態方法得到實例
            if (singleton1 == singleton2)
            {
                Console.WriteLine("兩個對象是相同的實例!");       //輸出 兩個對象是相同的示例
            }
            Console.ReadKey();
        }
    }  
}
複製代碼

  這種實現與前面的示例相似,也是解決了單例模式試圖解決的兩個基本問題:全局訪問和實例化控制,公共靜態屬性爲訪問實例提供了一個全局訪問點。不一樣之處在於它依賴公共語言運行庫來初始化變量。因爲構造方法是私有的,所以不能在類自己之外實例化Singleton類;所以,變量引用的是能夠再系統中存在的惟一實例。不過要注意,instance變量標記爲readonly,這意味着只能在靜態初始化期間或在類的構造函數中分配變量。因爲這種靜態初始化的方式是在本身被加載時就將本身實例化,因此被形象地稱之爲餓漢單例模式。而上面的第二種是在第一次被引用的時候,纔會將本身實例化,因此就被稱之爲懶漢單例模式

  因爲餓漢式,即靜態初始化的方式,它是類一加載就實例化對象,因此要提早佔用系統資源。然而懶漢式,又會面臨着多線程訪問的安全性問題,須要作雙重鎖定這樣的處理才能夠保證安全。因此到底使用哪種方式取決於實際的需求。從C#語言的角度來說,餓漢式的單例模式已經足夠知足咱們的需求。

相關文章
相關標籤/搜索