首页 > 代码库 > 单例模式
单例模式
单例模式的意图:保证一个类仅有一个实例,并提供一个该实例的全局访问点。要查看两个对象是不是同一个对象,可以通过 object.ReferenceEquals(a,b); 来查看
单线程下通过static来实现单例:
1 public class Singleton 2 { 3 private static Singleton instance = new Singleton(); 4 private Singleton{}; 5 6 public static Singleton Instance 7 { 8 get 9 {10 return instance;11 }12 }13 }
静态的字段的初始化是在第一次访问这个类的时候通过静态构造函数来创建的,而且静态的构造函数只是创建一次,所以能够保证只是执行一次。但是这种方式有一个问题,不能够实现延迟创建,也就是说不能够在需要使用这个对象的时候再创建它,下面这种方式就能够解决这种问题:
1 public class Singleton 2 { 3 //一个私有的静态字段,用来存储这个实例对象 4 private static Singleton instance; 5 private Singleton{};//设置成私有的,外部就不能够new了 6 //通过一个静态的只读属性来返回这个实例对象 7 public static Singleton Instance 8 { 9 get10 {11 if(instance == null)12 {13 //外部不能够new,但是类里面可以调用,因为类里面能够访问它的私有方法14 instance = new Singleton();15 }16 return instance;17 }18 }19 }
单线程的 Singleton 的几个要点:
- Singleton 模式中实例构造器可以设置为 protected 以允许子类去派生
- Singleton 模式一般不要支持 ICloneable 接口,因为这样可能会导致多个实例对象,与Singleton模式的初衷违背。ICloneable接口是用来实现对象的拷贝与克隆的
- Singleton 模式一般不要支持序列化,因为这样也有可能导致多个对象实例,同样与Singleton模式的初衷违背
- Singleton 模式只是考虑到了对象创建的管理,没有考虑到对象销毁的管理,当然就支持垃圾回收的平台和对象开销来讲,一般没有必要对齐销毁进行特殊的管理。垃圾回收是在类型卸载的时候回收的,Singleton是静态的,基本上是程序结束才会销毁。但因为Singleton只有一个对象,所以没有必要考虑
- Singleton 不能够应对多线程环境,在多线程环境下,使用Singleton模式任然可能得到Singleton类的多个实例对象。两个线程的访问同步到了if判断后创建实例对象前,那么每一个线程就会创建一个实例
多线程下单例模式的实现:
1 class Singleton 2 { 3 private Singleton(); 4 //volatile 可以保证编译器不会对这个代码进行微调 5 private static volatile Singleton instance = null; 6 //辅助对象,只要是一个Object对象就OK,也可以是外部的对象,主要是用来做双检查时的辅助 7 private static object lockHelper = new Object(); 8 //也可以改为一个方法来实现 9 public static Singleton Instance10 {11 get12 {13 if(instance == null)14 {15 //锁住,来进行双检查16 lock(lockHelper)17 {18 if(instance == null)19 {20 instance = new Singleton();21 }22 }23 }24 return instance;25 }26 }27 }28
还有一种比较好的方式来实现多线程下的单例模式:
1 class Singelton2 {3 private Singleton();4 //5 public static readonly Singleton Instance = new Singleton(); 6 }
这种模式同样也是通过构造函数来实现的,和下面的代码是等价的:
1 class Singleton 2 { 3 private Singleton(); 4 5 public static readonly Singleton Instance; 6 //一个静态的构造方法 7 //静态的构造方法是在类的第一次静态元素被访问的时候被调用的,而且只是执行一次。 8 //静态构造方法能够保证构造方法里面的代码只有一个线程只是执行一次,它会自动的枷锁。这是.NET类型初始化机制决定的 9 static Singleton10 {11 Instance = new Singleton();12 }13 }
这种模式下创建的单例模式也有一个不好的问题就是不支持参数化的创建,因为静态构造方法是操作系统调用的,而且不能够有参数的
支持参数化形式来创建单例模式,当然这个例子也仅仅只是改变两个字段的值
1 class Singleton 2 { 3 private Singleton(int x,int y) 4 { 5 this.x = x; 6 this.y = y; 7 } 8 int x; 9 int y;10 private static Singleton instance;11 12 public static Singleton(int x,int y)13 {14 if(instance == null)15 {16 instance = new Singleton(x,y);17 }18 else19 {20 instance.x = x;21 instance.y = y;22 }23 return instance;24 } 25 }
向上面这种参数化创建单例模式时,如果构造方法没有什么太多的工作,仅仅是该变一些属性等,可以定义一个可读可写的属性,然后再在调用得到实例化的对象后再改变属性的值。如果有太多其他的事情,也可以提供一个方法接口来实现,比如下面的方式:
1 class Singleton 2 { 3 private Singleton(int x,int y) 4 { 5 this.x = x; 6 this.y = y; 7 } 8 private int x,y; 9 public int X10 {11 get12 {13 return x;14 }15 set16 {17 x = value;18 }19 }20 public int Y21 {22 get23 {24 return y;25 }26 set27 {28 y = value;29 }30 }31 //保存实例对象的静态字段32 private static Singleton instance;33 34 public static Singleton(int x,int y)35 {36 if(instance == null)37 {38 instance = new Singleton(x,y);39 }40 else41 {42 instance.x = x;43 instance.y = y;44 }45 return instance;46 } 47 //提供一个公共的方法接口给外部来调用48 public void PubMethod(FileStream fs)49 {50 //代码51 }52 }
Singleton 模式的扩展
-> 将一个实例扩展到n个实例,比如对象池的实现。
这个n是代表的一个固定的个数,不是无限多个
-> 将new构造器的调用转移到其他的类中,比如多个类之间的协同工作环境中,某个局部环境只是需要拥有某个类的一个实例
-> 理解和扩展Singleton模式的核心“是如何控制用户使用new对一个类的实例构造器的任意调用”
.NET 框架中的Singleton的应用
-> 一个type对象就是一个Singleton对象。每一个对象只有一个全局唯一的Type对象
-> HttpContext 对象。他有一个 Current属性。这就是一个全局唯一的一个HttpContent属性