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、单例模式优缺点
优点
- 只有一个实例,减少了内存消耗和系统性能开销。
缺点
- 单例类的职责过重,在一定程度上违背了“单一职责原则”。
- 单例如果滥用会导致特殊一些问题。
- 单例类想扩展,只能修改源代码。有点违反开闭原则。