設計模式:單例模式


概述:像Windows系統的任務管理器一樣,你無論打開多少次,始終顯示的一個窗口。如何保證一個類只有一個實例並且這個實例易於被訪問呢,定義一個統一的全局變量可以確保對象隨時可以被訪問,但不能防止創建多個對象。一個最好的辦法就是讓類自身負責創建和保存它的唯一實例,並保證不創建其他實例,它還提供了一個訪問該實例的方法,這就是單例模式的動機。。一點都不雞凍-_-||。。

單例模式的定義:

  單例模式:確保一個類只有一個實例,並提供一個全局訪問點來訪問這個唯一實例。

  Singleton Pattern:Ensure  a class has only one instance, and provide a global point of access to it.

  單例模式是一種對象創建型模式。單例模式有三個要點:一是某個類只有一個實;二是它必須自行創建這個實例;三是它必須像整個系統提供這個實例。

單例模式的結構:

  單例模式是結構最簡單的設計模式,它只包含一個類,即單例類。

單例模式的實現:

    public class SingletonPattern
    {
        //靜態私有成員變量
        private static SingletonPattern instance = null;

        //私有化構造函數
        private SingletonPattern() { }

        //靜態私有工廠方法返回唯一實例
        public static SingletonPattern GetIstance()
        {
            if (instance == null)
                instance = new SingletonPattern();
            return instance;
        }
    }

  從代碼可以看出在實現單例模式的時候,需要注意一下三點:

    1:私有化構造函數private

    2:提供一個自身靜態私有成員變量

    3:提供一個公有的靜態工廠方法

  餓漢式單例(Eager Singleton):

    

  一:餓漢模式,代碼如下圖所以:

    public class EagerSingleton
    {
        private static EagerSingleton instance = new EagerSingleton();
        private EagerSingleton() { }    
        public static EagerSingleton GetInstance()
        {
            return instance;
        }
    }

  當類被加載的時候,靜態變量instance會被初始化,此時類的私有構造函數會被調用,單例類唯一實例將被創建。

 

  二:懶漢模式
    與餓漢模式單例類相同的是,懶漢式單例類(Lazy Singleton)的構造函數也是私有的,與餓漢式單例類不同的是,懶漢式單例類第一次被引用時將自己實例化,在懶漢式單例類加載時不會將自己實例化。

從圖中可以看出在懶漢單例類中,不是定義在靜態變量時實例化單例類,而是在第一次調用靜態工廠的時實例化單例類。

  代碼如下:

    public class LazySingleton
    {
        private static LazySingleton instance = null;

        //程序運行時創建一個靜態只讀的輔助對象
        private static readonly object syncRoot = new object();

        private LazySingleton() { }

        public static LazySingleton GetInstance()
        {
            //第一重判斷,先判斷實例是否存在,不存在再加鎖處理
            if(instance == null)
            {
                //加鎖的程序在某一時刻只允許一個線程訪問
                lock (syncRoot)
                {
                    //第二重判斷
                    if(instance == null)
                    {
                        instance = new LazySingleton();//創建單例實例
                    }
                }
            }
            return instance;
        }
    }

  從代碼中可以看到加鎖了,為什么加鎖呢? 是因為懶漢式單例存在一個嚴重的問題:如果在高並發、多線程環境下實現懶漢式單例,在某一時刻可能會有多個線程需要使用單例對象,即會有多個線程同時調用GetInstance()方法,可能會造成多個實例對象,這將違背單例模式的設計意圖。為了防止生成多個單例對象,需要使用lock關鍵字,lock關鍵字表示鎖定的代碼片段成為臨界區,可以確保一個線程位於代碼的臨界區。另一個線程不能進入臨界區。如果其他線程視圖進入鎖定的代碼,則將一直等待,知道該對象被釋放為止。

  餓漢式單例與懶漢式單例進行比較:

    餓漢式單例在類加載的時候就將自己實例化,它的優點在於無需考慮多個線程同時訪問的問題,可以確保實例的唯一性。從調用速度來講,由於單例對象一開始就得以創建,因此要優於懶漢式單例。但是無論系統在運行時是否需要使用該單例對象,由於在類加載時該對象就需要創建,因此從資源利用效率角度來京,餓漢式單例不急懶漢式單例,而且在系統加載時有序需要創建餓漢式單例對象,加載時間會比較長。

    懶漢式單例在第一次使用時創建,無需一直占用系統資源,實現了延遲加載,但是必須處理好多個線程同時訪問的問題,特別是當單例類作為資源控制器,在實例化時必然會涉及資源的初始化,而資源的初始化需要耗費大量的事件,這意味着出現多線程同時首次引用類的幾率變大,通過雙重檢查鎖定等機制進行控制,這將導致系統性能受到影響。

單例模式的優缺點:

  優點(1):提供了對唯一實例的受控訪問。

    (2):在系統內存中只存在一個對象,因此可以節約系統的資源,對於一些需要頻繁創建和銷毀的對象,使用單例模式無疑是提高了系統的性能。

    (3):單例模式允許可變數目的實例。基於單例模式可以進行擴展,使用與控制單例對象相似的方法獲得指定個數的實例對象,既節約了系統資源,又解決了由於單例對象共享過多有損性能的問題(自行提供指定數目實例對象的類可成為多例類)

  缺點(1):由於單例模式沒有抽象層,所以擴展起來很難。

    (2):單例類職責過重,在一定程度上違背了單一職責。因為單例類既提供了業務方法,又提供了創建對象的方法(工廠方法),將對象的創建和對象本身的功能耦合在一起。

    (3):垃圾回收機制,如果實例化的共享對象長時間不被利用,系統會認為它是垃圾,會自動銷毀並回收資源。在下次利用時又將重新實例化,這將導致共享單例對象狀態丟失。

單例模式的使用環境:

  單例模式作為一種目標明確、結構簡單、理解容易的設計模式,在軟件開發中使用頻率相當高,在很多應用軟件和框架中都得以廣泛的使用。

  在以下情況可以考慮使用單例模式:

  1:系統只需要一個實例對象,例如Windows資源管理器,或者因為資源消耗太大而只允許創建一個對象

  2:客戶調用類單個實例只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該實例。

 

如飢似渴的讀着23中設計模式,小弟不才,剛剛接觸到設計模式,汗啊-_-||,面向對象,面向對象,面向對象。重要的事情說三遍,接下來洗澡吃飯,回來繼續。

 


免責聲明!

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



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