单例模式以及在C#中的使用
下面做一些簡要的說明。
1.
單例模式(Singleton Pattern),又稱作單件模式,當(dāng)然也有一種詼諧的稱謂:單身模式。在經(jīng)典的GoF所著的《Design Patterns》一書中,對單例模式有著詳盡的介紹,這本書網(wǎng)上有全文版本。
?
2.
單例模式的意圖是保證一個類僅有一個實例,并且要提供一個全局訪問點來訪問這個實例。通常這個全局訪問點是一個靜態(tài)方法或者C#中的一個屬性。
?
3.
在C#中,典型的單例模式實現(xiàn)方法可以如下:
| 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; ????} } |
當(dāng)外部需要Manager的實例時,可以調(diào)用GetInstance()這個靜態(tài)方法。由于Manager類的構(gòu)造器是私有的,這也就避免了其他方式實例化這個Manager類。GetInstance()方法內(nèi)部的實現(xiàn),保證了全局中只有一個Manager實例。
?
4.
問題肯定不會這么簡單就被解決,比如在多線程環(huán)境中,上述代碼就會有很大的隱患。
- 有一種情況很常見:兩個線程同時調(diào)用GetInstance()方法;
- 當(dāng)某一個線程由于Mgr為null而進入條件判斷代碼塊的時候,而恰恰還沒有執(zhí)行實例化一個Manager對象,這時候另一個線程由于Mgr為null,所以也會進入這個條件語句中
上面兩種情況,很顯然都會創(chuàng)建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)的技術(shù),是為了提高性能考慮,因為C#中l(wèi)ock語句是很耗性能的。第一道檢查,是基于如果Mgr不為null的時候就不需要lock了,提高性能。第二道檢查,是基于兩個線程同時通過第一道檢查后,第一個線程解鎖后,由于Mgr此時已經(jīng)不為null,所以第二個線程就不用實例化Manager了。
?
5.
單例模式有兩種實現(xiàn)方式,主要基于構(gòu)建的方式不同:
前面創(chuàng)建單例模式的方式都屬于延遲初始化。.NET 4.0以后提供了一個Lazy<T>泛型類,可以被應(yīng)用于這個場景,省卻代碼的編寫量。
| 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>的構(gòu)造器重載版本可以幫我們解決多線程的問題。
C#使用靜態(tài)初始化來完成單例模式中的熱初始化。需要注意的是,不需要考慮多線程的問題,因為CLR會自動解決多線程同步的問題。如果程序經(jīng)常要用到這個實例,運用熱初始化可以顯著提高性能。
| public class Manager { ????private static readonly Manager mgr =?new Manager(); ????private Manager() { } ????public static Manager GetInstance() ????{ ????????return mgr; ????} } |
?
6.
StackOverflow中對于單例模式都是持否定態(tài)度的,比如這個:
In theory: when you need to restrict the instantiation of an object to one instance. In practice: never.
主要基于下面幾個原因:
- 違反了單一職責(zé)原則
- 耦合度過大
- 單元測試基本無法進行
- 開發(fā)混淆,造成混亂。比如作為API提供的時候。
總之,
There‘s at most a can use but there no need.
文章來源:http://laobian.me/2013/02/singleton-pattern-with-csharp.html
轉(zhuǎn)載于:https://www.cnblogs.com/luohengstudy/p/3141968.html
總結(jié)
以上是生活随笔為你收集整理的单例模式以及在C#中的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FreeSql (二十七)将已写好的 S
- 下一篇: dubbo-环境搭建,实现一个简单地du