文章目錄
前言
一、單例模式(Singleton Pattern)
二、使用步驟
角色
示例
總結
優點
缺點
使用場景
設計模式(Design pattern)是一套被反複使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人了解、保證代碼可靠性。 毫無疑問,設計模式于己于他人于系統都是多赢的,設計模式使代碼編制真正工程化,設計模式是軟體工程的基石,如同大廈的一塊塊磚石一樣。項目中合理的運用設計模式可以完美的解決很多問題,每種模式在現在中都有相應的原理來與之對應,每一個模式描述了一個在我們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是它能被廣泛應用的原因。
提示:以下是本篇文章正文内容,下面案例可供參考
單例模式屬于建立型模式,保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。
一個類有且僅有一個執行個體,并且自行執行個體化向整個系統提供。
1、單例類(Singleton)
保證唯一并提供全局通路點的單例類。
命名空間SingletonPattern中包含7個單例類,本案例将介紹這7種常見的單例實作方法。public sealed class Singleton {
private static Singleton _instance = null;
public static Singleton GetInstance() {
if(_instance == null) {
_instance = new Singleton();
Console.WriteLine("Singleton.GetInstance()!");
}
return _instance;
}
}
最常見的單例類,但是無法保證線程安全。因為首次運作時,n個線程可同時到達if(_instance == null),導緻_instance可能會被多初始化n-1次(有1次是需要初始化的)。在_instance被初始化之後新啟動的線程不會使該情況重制。
public sealed class SingletonSafe {
private static SingletonSafe _instance = null;
private static readonly object _lock = new object();
public static SingletonSafe GetInstance() {
lock (_lock) {
if (_instance == null) {
_instance = new SingletonSafe();
Console.WriteLine("SingletonSafe.GetInstance()!");
}
}
return _instance;
}
}
使用私有靜态object類型的鎖(微軟推薦),lock關鍵字會占有該鎖,之後請求該鎖的其它線程必需等待其釋放才能進入。該方法可實作線程安全的單例模式,但是鎖屬于昂貴資源,“占有鎖”和“釋放鎖”都比較耗時,并會在一定程度上阻止其它線程的執行,會顯著影響程式的并發性,是以有了下面的優化。
public sealed class SingletonSafe2 {
private static SingletonSafe2 _instance = null;
private static readonly object _lock = new object();
public static SingletonSafe2 GetInstance() {
if (_instance == null) {
lock (_lock) {
if (_instance == null) {
_instance = new SingletonSafe2();
Console.WriteLine("SingletonSafe2.GetInstance()!");
}
}
}
return _instance;
}
}
通過優先使用if (_instance == null)這種耗費資源較少的比較來決定是否進入鎖,可大幅度提高性能。因為_instance不為null時,直接傳回即可。
public sealed class SingletonLazy {
private static readonly Lazy<SingletonLazy> _instance =
new Lazy<SingletonLazy>(() => {
Console.WriteLine("SingletonLazy.GetInstance()!");
return new SingletonLazy();
});
public static SingletonLazy GetInstance() {
return _instance.Value;
}
}
帶泛型的Lazy式單例實作,這是線程安全的,僅提供給大家參考。
public sealed class SingletonReadOnly {
private static readonly SingletonReadOnly _instance =
new SingletonReadOnly();
public SingletonReadOnly() {
Console.WriteLine("SingletonReadOnly.GetInstance()!");
}
public static SingletonReadOnly GetInstance() {
return _instance;
}
}
靜态隻讀式單例實作(由運作時保證唯一),這是線程安全的,僅提供給大家參考。
public abstract class SingletonGenericBase<T> where T : class, new() {
private static T _instance = null;
private static readonly object _lock = new object();
public static T GetInstance() {
if (_instance == null) {
lock (_lock) {
if (_instance == null) {
_instance = new T();
Console.WriteLine("SingletonGeneric.GetInstance()!");
}
}
}
return _instance;
}
}
public sealed class SingletonGeneric : SingletonGenericBase<Singleton> {
public SingletonGeneric() { }
}
複雜的泛型實作,這是線程安全的,僅提供給大家參考。
public abstract class SingletonGenericBase2<T> where T : class {
private static readonly Lazy<T> _instance = new Lazy<T>(() => {
var ctors = typeof(T).GetConstructors(
BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Public);
if (ctors.Count() != 1)
throw new InvalidOperationException(
String.Format("Type {0} must have exactly one constructor.",
typeof(T)));
var ctor = ctors.SingleOrDefault(
c => !c.GetParameters().Any() && c.IsPrivate);
if (ctor == null)
throw new InvalidOperationException(
String.Format("The constructor for {0} must be private and take no parameters.",
typeof(T)));
Console.WriteLine("SingletonGeneric2.GetInstance()!");
return (T)ctor.Invoke(null);
});
public static T GetInstance() {
return _instance.Value;
}
}
public sealed class SingletonGeneric2 : SingletonGenericBase2<SingletonGeneric2> {
private SingletonGeneric2() { }
}
public class Program {
public static void Main(string[] args) {
var singleton = Singleton.GetInstance();
singleton = Singleton.GetInstance();
var singletonSafe = SingletonSafe.GetInstance();
singletonSafe = SingletonSafe.GetInstance();
var singletonSafe2 = SingletonSafe2.GetInstance();
singletonSafe2 = SingletonSafe2.GetInstance();
var singletonReadOnly = SingletonReadOnly.GetInstance();
singletonReadOnly = SingletonReadOnly.GetInstance();
var singletonLazy = SingletonLazy.GetInstance();
singletonLazy = SingletonLazy.GetInstance();
var singletonGeneric = SingletonGeneric.GetInstance();
singletonGeneric = SingletonGeneric.GetInstance();
var singletonGeneric2 = SingletonGeneric2.GetInstance();
singletonGeneric2 = SingletonGeneric2.GetInstance();
Console.ReadKey();
}
}
以上是調用方的代碼,每個GetInstance方法均調用2次以展示效果。以下是這個案例的輸出結果:
Singleton.GetInstance()!
SingletonSafe.GetInstance()!
SingletonSafe2.GetInstance()!
SingletonReadOnly.GetInstance()!
SingletonLazy.GetInstance()!
SingletonGeneric.GetInstance()!
SingletonGeneric2.GetInstance()!
1、單例模式會阻止其他對象執行個體化其自己的單例對象的副本,進而確定所有對象都通路唯一執行個體;
2、因為類控制了執行個體化過程,是以類可以靈活更改執行個體化過程。
1、沒有接口,不能繼承,與單一職責原則沖突。
1、需要頻繁的進行建立和銷毀的對象;
2、建立對象時耗時過多或耗費資源過多,但又經常用到的對象;
3、工具類對象;
4、頻繁通路資料庫或檔案的對象。