1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
方法1
不推薦的方式1:只能用於單線程。
因為有可能會出現兩個線程同時判斷 _instance==null 然后都創建一個實例。這就不滿足單例模式了。
//sealed修飾符,不可被繼承或重寫
public sealed class Singleton1
{
private static Singleton1 _instance = null;
public static Singleton1 Instance
{
get
{
if (_instance == null)
_instance = new Singleton1();
return _instance;
}
}
}
方法2
不推薦的方式2:雖然能多線程但效率不高。
這樣當一個線程加鎖時,另一個線程只能等待。但是加鎖比較耗時,所以效率比較低。
public sealed class Singleton2
{
//readonly動態變量修飾符
private static readonly object locked = new object();
private static Singleton2 _instance = null;
public static Singleton2 Instance
{
get
{
lock (locked)
{
if (_instance == null)
_instance = new Singleton2();
}
return _instance;
}
}
}
方法3
還可以的方式3:前后兩次if語句判斷。
在加鎖前再判斷一次是否為空,這樣就只會在第一次創建的時候加鎖了。但是此方法比較麻煩,還有更好的方法。
public sealed class Singleton3
{
private static readonly object locked = new object();
private static Singleton3 _instance = null;
public static Singleton3 Instance
{
get
{
//這樣不為空時,就不會再加鎖
if (_instance == null)
{
lock (locked)
{
if (_instance == null)
_instance = new Singleton3();
}
}
return _instance;
}
}
}
方法4
推薦的方式4:靜態構造函數。
靜態構造函數的調用並不是由程序員決定的,而是在第一次用到Singleton4時就會被調用。所以有可能我們還沒有調用 Singleton4.Instance 的時候就已經被創建了,可能會降低內存使用效率。
public sealed class Singleton4
{
//靜態變量在靜態構造函數被調用時初始化,所以只會初始化一次
private static Singleton4 _instance = new Singleton4();
public static Singleton4 Instance
{
get
{
return _instance;
}
}
}
方法5
推薦的方式5:按需創建實例。
由Nested的靜態成員完成,實現按需初始化。
public sealed class Singleton5
{
public static Singleton5 Instance
{
get
{
return Nested._instance;
}
}
class Nested
{
static Nested()
{
}
//internal修飾符。只有同一個程序集可訪問,可以跨類。
internal static readonly Singleton5 _instance = new Singleton5();
}
}
2、單例模式優缺點
優點
- 只有一個實例,減少了內存消耗和系統性能開銷。
缺點
- 單例類的職責過重,在一定程度上違背了“單一職責原則”。
- 單例如果濫用會導致特殊一些問題。
- 單例類想擴展,只能修改源代碼。有點違反開閉原則。