今天我们来说说在编程时候我们最常见也是最好用的一种单例模式 。单例模式太简单了,让一个类变成只有一个唯一的对象类,方便客户对象调用。那这有什么好说的呢,我们先来看看一个普通的单例模式代码。
Singleton 模式中的实例和构造器可以设置为protected以允许子类派生
Singleton 模式一般不要支持ICloneable接口,因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
Singleton 模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。
Singleton 模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来讲,我们一般没有必要对其销毁进行特殊的管理。不能应对多线程环境:在多线程环境中,使用Singleton模式仍然有可能得到Singleton类的多个实例对象。
上面就是单例模式的几个使用注意事项,也就是说,我们平时如果是这样写出来的单例模式其实是不安全的,不能保证在多线程下的唯一性。
那怎么办呢,其实我们可以尝试修改成其他写法。
可能你会说,这样的单例是不是有点太麻烦,有没有更简单的办法?答案是有,下面我们来看最简单的一种:
好了,这就是单例模式的一些小细节的处理,代码比较少,但是都比较实用,希望可以帮助到大家。
public class Singleton
{
private static Singleton instance;
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
这个普通的单例模式,其实还是会有几个要点,我们先来看看Singleton 模式中的实例和构造器可以设置为protected以允许子类派生
Singleton 模式一般不要支持ICloneable接口,因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
Singleton 模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。
Singleton 模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来讲,我们一般没有必要对其销毁进行特殊的管理。不能应对多线程环境:在多线程环境中,使用Singleton模式仍然有可能得到Singleton类的多个实例对象。
上面就是单例模式的几个使用注意事项,也就是说,我们平时如果是这样写出来的单例模式其实是不安全的,不能保证在多线程下的唯一性。
那怎么办呢,其实我们可以尝试修改成其他写法。
public class Singleton
{
private static volatile Singleton instance=null;
private static object lockHelper = new object();
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockHelper)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
现在我们重新修改了一遍,首先新添加了一个object类型的数据对象,然后每次在get单例的时候先检查是否为空,然后在锁住当前进程,然后再次检查,最后在new出这个单例。使用了Double Check 双层检查的方式,这样就能有效的避免了多线程环境下无法保证单例唯一性。对了, 我们在私有的instance中 在static后面还添加了volatile修饰符,这个修饰符的作用是可以保证程序不会对程序进行排序,微调。这样就可以严格的确保了对象构造的顺序。可能你会说,这样的单例是不是有点太麻烦,有没有更简单的办法?答案是有,下面我们来看最简单的一种:
public class Singleton
{
public static readonly Singleton Instance = new Singleton();
private Singleton() { }
}
这次是不是更简单了呢, 这次简单的原因是使用了readonly 修饰符。单例模式的初始化由前面的static静态函数实现,然后在运行时编译,当这个类被加载的时候,会自动实例化这个类,就不用在后面调用get才实例化出唯一的对象了,而且无需我们关心线程安全性问题,底层会自动解决。但是小有小的好处,也不可避免带来一点麻烦,比如这样写的话就不支持构造器接受参数了,所以我们得小拆分下,让程序变得更灵活。public class Singleton
{
public static readonly Singleton Instance;
static Singleton()
{
Instance = new Singleton();
}
private Singleton() { }
}
现在我们把new的那块代码拆分,留到构造器实例化重新生成,这样就可以使用重载来另外加带传参的方法了。好了,这就是单例模式的一些小细节的处理,代码比较少,但是都比较实用,希望可以帮助到大家。