什么是单例模式
一个类只能创建一个实例(对象),那么这个类就是一个单例类,这种模式就叫单例模式。单例模式的唯一性由开发者自己控制,可以是进程(服务)唯一,也可以是线程唯一,或者是集群唯一。这些都属于单例。
单例模式用来解决一些资源冲突的问题,和一些没有状态的类也可以设计成单例模式。
实现方式
-
饿汉模式
在程序加载的时候就初始化单例类。所以饿汉模式是线程安全的。
/// <summary>
/// 单例模式.
/// </summary>
public class SingletonClass
{
private static SingletonClass _singletonClass=new SingletonClass();
/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
private SingletonClass()
{
}
/// <summary>
/// 对外公开的创建对象方法
/// </summary>
/// <returns></returns>
public static SingletonClass CreateSingletonClass()
{
return _singletonClass;
}
}
-
懒汉模式
在程序调用的时候就才进行类的初始化,类似延迟加载。但是对于一些初始化需要耗时比较久的单例类还是推荐在程序启动的时候就进行初始化。懒汉模式并不是线程安全的,获取的时候需要进行上锁,避免重复创建。
public class SingletonClass
{
private static SingletonClass _singletonClass;
private static readonly object Lock = new object();
private static SingletonClass _instance;
/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
private SingletonClass()
{
}
private static class ReturnSingletonClass
{
public static SingletonClass instance = new SingletonClass();
}
/// <summary>
/// 对外公开的创建对象方法
/// </summary>
/// <returns></returns>
public static SingletonClass CreateSingletonClass()
{
// 提前判断,防止每次都需要上锁
if (_singletonClass == null)
{
lock (Lock) //防止多线程重复创建
{
if (_singletonClass != null) return _singletonClass ?? (_singletonClass = new SingletonClass());
return _singletonClass = new SingletonClass();
}
}
return _singletonClass;
}
}
-
内部静态类实现懒加载
必须提供一个默认的构造函数。否则CLR在调动静态类之前初始化你的静态成员。那就和饿汉模式一样。内部静态类是线程安全的。
BeforeFieldInit:如果一个类没有静态构造函数,那么它应该被标记为BeforeFieldInit。这个类的初始化工作有可能早于晚于或者就在这个类的静态属性被访问时完成。
public class SingletonClass
{
/// <summary>
/// 私有化构造函数,防止外部创建
/// </summary>
private SingletonClass()
{
}
/// <summary>
/// 内部静态类实现
/// </summary>
private static class ReturnSingletonClass
{
public static SingletonClass _instance = new SingletonClass();
// 当有静态构造函数时,不会被beforefieldinit修饰
static ReturnSingletonClass()
{
}
}
/// <summary>
/// 对外公开的创建对象方法
/// </summary>
/// <returns></returns>
public static SingletonClass CreateSingletonClass()
{
return ReturnSingletonClass._instance;
}
}
备注
单例模式对oop特性支持不好,扩展性基本没有,如果需要添加新功能只能修改源码。如果单例类并没有后续扩展的需求,并且不依赖外部系统,那设计成单例类就没有太大问题。还可以通过工厂模式,静态方法,ioc注入等方式来替代单例。