单例模式以及在C#中的使用
下面做一些簡要的說明。
1.
單例模式(Singleton Pattern),又稱作單件模式,當然也有一種詼諧的稱謂:單身模式。在經典的GoF所著的《Design Patterns》一書中,對單例模式有著詳盡的介紹,這本書網上有全文版本。
?
2.
單例模式的意圖是保證一個類僅有一個實例,并且要提供一個全局訪問點來訪問這個實例。通常這個全局訪問點是一個靜態方法或者C#中的一個屬性。
?
3.
在C#中,典型的單例模式實現方法可以如下:
| public class Manager { ????private static Manager Mgr; ????//constructor must be private ????private Manager() { } ????//public and static, or you can change it to Property instead of Method. ????public static Manager GetInstance() ????{ ????????if (Mgr ==?null) ????????{ ????????????Mgr =?new Manager(); ????????} ????????return Mgr; ????} } |
當外部需要Manager的實例時,可以調用GetInstance()這個靜態方法。由于Manager類的構造器是私有的,這也就避免了其他方式實例化這個Manager類。GetInstance()方法內部的實現,保證了全局中只有一個Manager實例。
?
4.
問題肯定不會這么簡單就被解決,比如在多線程環境中,上述代碼就會有很大的隱患。
- 有一種情況很常見:兩個線程同時調用GetInstance()方法;
- 當某一個線程由于Mgr為null而進入條件判斷代碼塊的時候,而恰恰還沒有執行實例化一個Manager對象,這時候另一個線程由于Mgr為null,所以也會進入這個條件語句中
上面兩種情況,很顯然都會創建Manager實例,這也就違背了單例模式的意圖了。
利用C#的特性,我們可以把一個線程先鎖住(lock),等到這個線程完成后,再讓下一個線程訪問GetInstance()方法:
| private static readonly object syncObject =?new object(); //public and static, or you can change it to Property instead of Method. public static Manager GetInstance() { ????//double check ????if (Mgr ==?null) ????{ ????????lock (syncObject) ????????{ ????????????if (Mgr ==?null) ????????????{ ????????????????Mgr =?new Manager(); ????????????} ????????} ????} ????return Mgr; } |
代碼中用到了雙重檢查鎖定(double check locking)的技術,是為了提高性能考慮,因為C#中lock語句是很耗性能的。第一道檢查,是基于如果Mgr不為null的時候就不需要lock了,提高性能。第二道檢查,是基于兩個線程同時通過第一道檢查后,第一個線程解鎖后,由于Mgr此時已經不為null,所以第二個線程就不用實例化Manager了。
?
5.
單例模式有兩種實現方式,主要基于構建的方式不同:
前面創建單例模式的方式都屬于延遲初始化。.NET 4.0以后提供了一個Lazy<T>泛型類,可以被應用于這個場景,省卻代碼的編寫量。
| public class Manager { ????private static Lazy<Manager> mgr =?new Lazy<Manager>(); ????? ????//version of Thread Safe ????//private static Lazy<Manager> mgr = new Lazy<Manager>(true); ????? ????private Manager() { } ????public static Manager GetInstance() ????{ ????????return mgr.Value; ????} } |
Lazy<T>的構造器重載版本可以幫我們解決多線程的問題。
C#使用靜態初始化來完成單例模式中的熱初始化。需要注意的是,不需要考慮多線程的問題,因為CLR會自動解決多線程同步的問題。如果程序經常要用到這個實例,運用熱初始化可以顯著提高性能。
| public class Manager { ????private static readonly Manager mgr =?new Manager(); ????private Manager() { } ????public static Manager GetInstance() ????{ ????????return mgr; ????} } |
?
6.
StackOverflow中對于單例模式都是持否定態度的,比如這個:
In theory: when you need to restrict the instantiation of an object to one instance. In practice: never.
主要基于下面幾個原因:
- 違反了單一職責原則
- 耦合度過大
- 單元測試基本無法進行
- 開發混淆,造成混亂。比如作為API提供的時候。
總之,
There‘s at most a can use but there no need.
文章來源:http://laobian.me/2013/02/singleton-pattern-with-csharp.html
轉載于:https://www.cnblogs.com/luohengstudy/p/3141968.html
總結
以上是生活随笔為你收集整理的单例模式以及在C#中的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FreeSql (二十七)将已写好的 S
- 下一篇: C# 运行时通过鼠标拖动改变控件的大小