一、动机(motivation)
在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
这应该是类设计者的责任,而不是使用者的责任。
二、意图(intent)
保证一个类仅有一个实例,并提供一个该实例的全局访问点
三、结构(structure)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
四、单例模式的代码实现
1、单线程singleton模式的实现
public sealed class singleton { private static singleton uniqueinstance;// 定义一个静态变量来保存类的实例 private singleton() // 定义私有构造函数,使外界不能创建该类实例 { } /// /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 /// /// public static singleton getinstance() { if (uniqueinstance == null)// 如果类的实例不存在则创建,否则直接返回 { uniqueinstance = new singleton(); } return uniqueinstance; } }
私有的实例构造器是为了屏蔽默认产生的构造器,让类的使用者无法调用构造器。
单线程singleton模式的几个要点
singleton模式中的实例构造器可以设置为protected以允许子类派生。
singleton模式一般不要支持icloneable接口,因为这可能会导致多个对象实例,与singleton模式的初衷违背。
singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与singleton模式的初衷违背。
singleton模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收平台和对象的开销来讲,我们一般没有必要对其销毁进行特殊的管理。
不能应对多线程环境:在多线程环境下,使用singleton模式仍然有可能得到singleton类的多个实例对象。
2、双多线程重锁定(double check)singleton模式的实现
public sealed class singleton { private static volatile singleton uniqueinstance;// volatile关键字知识此成员变量能被多个线程访问。 private static readonly object locker = new object();// 定义一个标识确保线程同步 private singleton()// 定义私有构造函数,使外界不能创建该类实例 { } public static singleton getinstance() { if (uniqueinstance == null)//先判断不存在再枷锁 { lock (locker) { if (uniqueinstance == null)// 如果类的实例不存在则创建,否则直接返回 { uniqueinstance = new singleton(); } } } return uniqueinstance; } }
volatile修饰符:编译器在编译代码的时候会对代码的顺序进行微调,用volatile修饰保证了严格意义的顺序。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
3、使用c#语言的“静态初始化”特性来实现单例的singleton模式。(.net中实现singleton的首选方法)
内联初始化(生成的同时进行初始化):
public sealed class singleton { private static readonly singleton instance = new singleton(); public static singleton getinstance() { return singleton.instance; } private singleton()//私有构造函数,防止外界调用 { //... } }
它等同于:
public sealed class singleton { public static readonly singleton instance; //静态构造函数,初始化静态变量。clr只执行一次 static singleton() { instance = new singleton(); } public static singleton getinstance() { return singleton.instance; } private singleton()//私有构造函数,防止外界调用 { //... } }
另一种优雅写法是要用到.net 4.0里lazy
public sealed class singleton { private static readonly lazy lazy = new lazy(() => new singleton()); public static singleton instance => lazy.value; private singleton() { } }
只要想访问静态字段,必定已经在之前执行了静态构造器。这样也能够精确地保证使用的时候一定能拿到实例,如果不使用也不会实例化对象,也就是延时加载的功能。他同样能够支持多线程环境,因为只可能有一个线程执行静态构造器,不可能有多个线程去执行静态构造器,感觉就是程序已经自动为我们加锁了。它的一点弊端就是它不支持参数化的实例化方法。
在.net里静态构造器只能声明一个,而且必须是无参数的,私有的。因此这种方式只适用于无参数的构造函数。
五、.net框架中的singleton应用
t1==t2 这说明,gettype方法获得的type实例都是单例。
httpcontext.current也是如此,他们是通过singleton的扩展方式实现的,他们的单例也并不是覆盖所有领域,只是针对某些局部领域中,是单例的,不同的领域中还是会有不同的实例。
到此这篇关于.net设计模式之单例模式(singleton)的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持代码网。
发表评论