您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關C#中怎么實現單例模式,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
單例模式的介紹
2.1、動機(Motivate)
在軟件系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個實例,才能確保它們的邏輯正確性、以及良好的效率。
如何繞過常規的構造器,提供一種機制來保證一個類只有一個實例?
這應該是類設計者的責任,而不是使用者的責任
2.2、意圖(Intent)
保證一個類僅有一個實例,并提供一個該實例的全局訪問點。 --《設計模式GoF》
2.3、結構圖(Structure)
2.4、模式的組成
(1)、單件實例(Singleton):這個模式里面只有一個類型,就是Singleton類型,并且這個類只有一個實例,可以通過Instance()方法獲取該類型的實例。
2.5、單件模式的代碼實現
既然是單實例,肯定會涉及到多線程的問題,我們就一步一步的來寫代碼,我們先看看單線程Singleton模式的實現,代碼如下:
私有的實例構造器是屏蔽外界的調用,上面的單例模式的實現在單線程下確實是完美的,也很好的滿足了我們單線程環境的需求。
單線程單例模式的幾個要點:
(1)、Singleton模式中的實例構造器可以設置為protected以允許子類派生。
(2)、Singleton模式一般不要支持ICloneable接口,因為這可能會導致多個對象實例,與Singleton模式的初衷違背。
(3)、Singleton模式一般不要支持序列化,因為這也有可能導致多個對象實例,同樣與Singleton模式的初衷違背。
(4)、Singletom模式只考慮到了對象創建的工作,沒有考慮對象銷毀的工作。為什么這樣做呢,因為Net平臺是支持垃圾回收的,所以我們一般沒有必要對其進行銷毀處理。
(5)、不能應對多線程環境:在多線程環境下,使用Singleton模式仍然有可能得到Singleton類的多個實例對象
如果放在多線程環境下,問題就出來了。因為在兩個線程同時運行GetInstance方法時,此時兩個線程判斷(uniqueInstance ==null)這個條件時都返回真,此時兩個線程就都會創建Singleton的實例,這樣就違背了我們單例模式初衷了。要想解決這個問題,只要讓GetInstance方法在同一時間只運行一個線程運行就好了,讓我們看看多線程Singleton模式的實現,代碼如下:
上面這種解決方案確實可以解決多線程的問題,但是上面代碼對于每個線程都會對線程輔助對象locker加鎖之后再判斷實例是否存在,對于這個操作完全沒有必要的,因為當第一個線程創建了該類的實例之后,后面的線程此時只需要直接判斷(uniqueInstance==null)為假,此時完全沒必要對線程輔助對象加鎖之后再去判斷,所以上面的實現方式增加了額外的開銷,損失了性能,為了改進上面實現方式的缺陷,我們只需要在lock語句前面加一句(uniqueInstance==null)的判斷就可以避免鎖所增加的額外開銷,這種實現方式我們就叫它 “雙重鎖定(Double Check)”,下面具體看看實現代碼的:
volatile修飾:編譯器在編譯代碼的時候會對代碼的順序進行微調,用volatile修飾保證了嚴格意義的順序。一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。
三、C#中實現了單例模式的類
現在我們看看,如何使用C#語言的特性來實現單例的Singleton模式。
內聯初始化其實是把靜態的字段放到靜態構造器去初始化。只要想訪問靜態字段,必定已經在之前執行了靜態構造器。這樣也能夠精確地保證使用的時候一定能拿到實例,如果不使用也不會實例化對象,也就是延時加載的功能。他同樣能夠支持多線程環境,因為只可能有一個線程執行靜態構造器,不可能有多個線程去執行靜態構造器,感覺就是程序已經自動為我們加鎖了。
它的一點弊端就是它不支持參數化的實例化方法。在.NET里靜態構造器只能聲明一個,而且必須是無參數的,私有的。因此這種方式只適用于無參數的構造器。
需要說明的是:HttpContext.Current就是一個單例,他們是通過Singleton的擴展方式實現的,他們的單例也并不是覆蓋所有領域,只是針對某些局部領域中,是單例的,不同的領域中還是會有不同的實例。
四、Singleton模式的擴展
(1)、將一個實例擴展到n個實例,例如對象池的實現。(n不是指無限個實例,而是固定的某個數)
(2)、將new構造器的調用轉移到其他類中,例如多個類協同工作環境中,某個局部環境只需要擁有某個類的一個實例。
(3)、理解和擴展Singleton模式的核心是“如何控制用戶使用new對一個類的實例構造器的任意調用”。
五、單例模式的實現要點
1、Singleton模式是限制而不是改進類的創建。
2、Singleton類中的實例構造器可以設置為Protected以允許子類派生。
3、Singleton模式一般不要支持Icloneable接口,因為這可能導致多個對象實例,與Singleton模式的初衷違背。
4、Singleton模式一般不要支持序列化,這也有可能導致多個對象實例,這也與Singleton模式的初衷違背。
5、Singleton只考慮了對象創建的管理,沒有考慮到銷毀的管理,就支持垃圾回收的平臺和對象的開銷來講,我們一般沒必要對其銷毀進行特殊的管理。
6、理解和擴展Singleton模式的核心是“如何控制用戶使用new對一個類的構造器的任意調用”。
7、可以很簡單的修改一個Singleton,使它有少數幾個實例,這樣做是允許的而且是有意義的。
1】、單例模式的優點:
(1)、實例控制:Singleton 會阻止其他對象實例化其自己的 Singleton 對象的副本,從而確保所有對象都訪問唯一實例
(2)、靈活性:因為類控制了實例化過程,所以類可以更加靈活修改實例化過程
2】、單例模式的缺點:
(1)、開銷:雖然數量很少,但如果每次對象請求引用時都要檢查是否存在類的實例,將仍然需要一些開銷。可以通過使用靜態初始化解決此問題。
(2)、可能的開發混淆:使用 singleton 對象(尤其在類庫中定義的對象)時,開發人員必須記住自己不能使用 new 關鍵字實例化對象。因為可能無法訪問庫源代碼,因此應用程序開發人員可能會意外發現自己無法直接實例化此類。
(3)、對象的生存期:Singleton 不能解決刪除單個對象的問題。因為它包含對該靜態的私有字段的引用,靜態字段是不能被CLR回收內存的,該實例會和應用程序生命周期一樣長,一直存在。
3】、單例模式的使用場合:
(1)、當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。
(2)、當這個唯一實例應該是通過子類化可擴展的,并且客戶應該無需更改代碼就能使用一個擴展的實例時。
上述就是小編為大家分享的C#中怎么實現單例模式了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。