C#设计模式之一单例模式(Singleton Pattern)【创建型】
一、引言 ??? 从目的来看: ?????? -创建型(Creational)模式:负责对象创建 ?????? -结构型(Structural)模式:处理类与对象间的组合 ?????? -行为型(Behavioral)模式:类与对象交互中的职责分配 ?? 从范围来看: ????? -类模式处理类与子类的静态关系 ????? -对象模式处理对象间的动态关系 ? 以上就是分类的方式,我们按大多数的分类,采用“从目的来看”的分类来对设计模式进行分类,我们就开始今天的学习吧。 ????????? 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。 ?? 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例? ???????? 这应该是类设计者的责任,而不是使用者的责任 ?? 2.2、意图(Intent) ???????? 保证一个类仅有一个实例,并提供一个该实例的全局访问点。 ?????????? --《设计模式GoF》 ?? 2.3、结构图(Structure) ?????? ? 2.4、模式的组成 ???????? (1)、单件实例(Singleton):这个模式里面只有一个类型,就是Singleton类型,并且这个类只有一个实例,可以通过Instance()方法获取该类型的实例。 ? 2.5、单件模式的代码实现 1 /// <summary>
2 /// 单例模式的实现
3 </summary>
4 public sealed class Singleton
5 {
6 // 定义一个静态变量来保存类的实例
7 private static Singleton uniqueInstance;
8
9 定义私有构造函数,使外界不能创建该类实例
10 private Singleton()
11 {
12 }
13
14 15 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
16 17 <returns></returns>
18 public Singleton GetInstance()
19 20 如果类的实例不存在则创建,否则直接返回
21 if (uniqueInstance == null)
22 {
23 uniqueInstance = new Singleton();
24 }
25 return uniqueInstance;
26 27 }
??? 单线程单例模式的几个要点:
1 2 3 4 6 7 volatile Singleton uniqueInstance;
9 定义一个标识确保线程同步
10 static readonly object locker = new object();
11
12 13 14 15 16
17 18 19 20 23 当第一个线程运行到这里时,此时会对locker对象 "加锁",
24 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
25 lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
26 lock (locker)
27 {
28 29 30 {
31 uniqueInstance = 32 }
33 }
34
35 36 37 }
??? 上面这种解决方案确实可以解决多线程的问题,但是上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(uniqueInstance==null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前面加一句(uniqueInstance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定(Double Check)”,下面具体看看实现代码的: volatile 双重锁定只需要一句判断就可以了 27 if (uniqueInstance == 28 31 32 { 34 uniqueInstance = 35 } 37 38 39 40 } ? ? ? ? volatile修饰:编译器在编译代码的时候会对代码的顺序进行微调,用volatile修饰保证了严格意义的顺序。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。 Singleton模式的实现
sealed Singleton
{
readonly Singleton instance= Singleton();
Singleton(){}
}
以上是内联初始化(生成的同时进行初始化)的单例模式,它等同于:
Singleton
{
readonly Singleton instance;
静态构造函数,CLR只执行一次
Singleton()
{
instance= Singleton();
}
私有构造函数,防止外界调用
Singleton(){}
}
??? 内联初始化其实是把静态的字段放到静态构造器去初始化。只要想访问静态字段,必定已经在之前执行了静态构造器。这样也能够精确地保证使用的时候一定能拿到实例,如果不使用也不会实例化对象,也就是延时加载的功能。他同样能够支持多线程环境,因为只可能有一个线程执行静态构造器,不可能有多个线程去执行静态构造器,感觉就是程序已经自动为我们加锁了。 ???? 需要说明的是:HttpContext.Current就是一个单例,他们是通过Singleton的扩展方式实现的,他们的单例也并不是覆盖所有领域,只是针对某些局部领域中,是单例的,不同的领域中还是会有不同的实例。 四、Singleton模式的扩展 ???? (1)、将一个实例扩展到n个实例,例如对象池的实现。(n不是指无限个实例,而是固定的某个数) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |