C#單例模式之懶漢 / 餓漢


在使用某個設計模式之前必須先了解使用它的優點:

1、單例模式就是保證在整個應用程序的生命周期中,在任何時刻,被指定的類只有一個實例對象,減少了對象的創建,從而減輕了程序內存的開銷。

2、單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。
3、說白了就是保證一個類僅有一個實例,並提供一個該實例的全局訪問點用於輸出實例。

應用場景:
1. Windows的Task Manager(任務管理器)就是很典型的單例模式,任何時候只能打開一個窗口。
  2. windows的Recycle Bin(回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護着僅有的一個實例。


  3. 網站的計數器,一般也是采用單例模式實現,否則難以同步。
  4. 應用程序的日志應用,一般都何用單例模式實現,這一般是由於共享的日志文件一直處於打開狀態,因為只能有一個實例去操作,否則內容不好追加。
5. Web應用的配置對象的讀取,一般也應用單例模式,這個是由於配置文件是共享的資源。
  6. 數據庫連接池的設計一般也是采用單例模式,因為數據庫連接是一種數據庫資源。數據庫軟件系統中使用數據庫連接池,主要是節省打開或者關閉數據庫連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因為何用單例模式來維護,就可以大大降低這種損耗。
  7. 多線程的線程池的設計一般也是采用單例模式,這是由於線程池要方便對池中的線程進行控制。
  8. 操作系統的文件系統,也是大的單例模式實現的具體例子,一個操作系統只能有一個文件系統。

代碼實現(懶漢模式:在第一次被引用時將自己實例化):
1.將被調用類的構造方法定義為私有方法,這樣其他處的代碼就無法通過調用該類的構造方法來實例化該類的對象,只有通過該類提供的靜態方法來得到該類的唯一實例;(防止調用者直接實例化被調用類

2.在該類內提供一個靜態方法,當我們調用這個方法時,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就創建該類的實例並將實例的引用賦予該類保持的引用。
3.創建訪問者對象(用於加鎖防止並發)

4.創建全局訪問點(輸出實例):所以該方法絕對不能是 private不然其他類無法調用該方法,並且必須是靜態的方法因為 本類構造函數為

私有的外部無法實例化本類(前面已經講了),所以只能通過 類名 .(點) 方法名來調用該方法。不然你在創建的這個類就是廢類別人無法使用

使用雙重鎖來防止多線程調用出現的並發問題:

當Single為null並且同時有兩個線程調用
GetInstance方法時,他們將都可以通過第
一重Single==null的判斷,然后由於lock
機制,這兩個線程則只有一個進入,另一
個在外排隊等候,必須要其中的一個進入
並出來后,另一個才能進入。而此時如果
沒有了第二重的Single是否為null的判斷,
則第一個線程創建了實例,而第二個線程
還是可以繼續在創建新的實例,這就沒有
達到單例的目的。

5.調用

(餓漢模式:加載時就將自己實例化給調用者使用)

注意:此時服務對象已經在程序加載時賦值為該類實例(但是只賦值一次,因為 static readonly是使用靜態構造函數賦值)

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

由於餓漢式,即靜態初始化的方式,它是類一加載就實例化的對象,所以要提前占用系統資源。然后懶漢式,又會面臨着多線程訪問的安全性問題,需要做雙重鎖定這樣的處理才可以保證安全。所以到底使用哪一種方式,取決於實際的需求。從C#語言角度來講,餓漢式的單例類已經足夠滿足我們的需求了。

 


免責聲明!

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



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