概述:像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中設計模式,小弟不才,剛剛接觸到設計模式,汗啊-_-||,面向對象,面向對象,面向對象。重要的事情說三遍,接下來洗澡吃飯,回來繼續。