单例模式:
核心思想:类只实例化一次,并且提供一个全局访问点。(只有那个全局访问点对外开放,其他内容封装起来)
图片解析:
优点:
1》由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能
2》直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的 singleton。
代码:
第一版本:(在单线程里面使用(不考虑线程内安全问题))
主要分为三步:1、静态实例变量(用于接收实例成员)2、构造函数私有化(外部不能实例化,不能获得实例)3、全局访问点(任何用户都从这里访问)
1 //sealed:私有类:太监类(不能被继承) 2 public sealed class Singleton 3 { 4 //第一步:创建一个 静态 私有的变量(用于接收 对象的实例) 5 private static Singleton instance; 6 7 //第二步:构造函数私有化(不能实例化) 8 private Singleton() 9 { 10 } 11 13 14 //第三步:单例函数的“全局入口点” 静态 15 public static Singleton Instance 16 { 17 get 18 { 19 //(唯一实例):没有就进行创建,有的话就不创建 20 if (instance == null) 21 { 22 instance = new Singleton(); 23 } 24 return instance; 25 } 26 } 27 }
第二版本:(解决线程内安全问题)
使用lock锁的机制,解决多线程问题。但是在性能上降低的
1 //sealed:私有类:太监类(不能被继承) 2 public sealed class Singleton 3 { 4 //第一步:创建一个 静态 私有的变量(用于接收 对象的实例) 5 private static Singleton instance; 6 7 //第二步:构造函数私有化(不能实例化) 8 private Singleton() 9 { 10 } 11 12 //第一版本的单例设计模式 13 14 //第三步:单例函数的“全局入口点” 静态 15 public static Singleton Instance 16 { 17 get 18 { 19 //(唯一实例):没有就进行创建,有的话就不创建 20 if (instance == null) 21 { 22 instance = new Singleton(); 23 } 24 return instance; 25 } 26 } 27 }
3.第三版本:双重锁定机制
优点:
1》多线程安全
2》(*重点*)线程不是每次都加锁(单线程不用加lock,性能提升了)
3》允许实例化延迟到第一次访问对象时发生(只有第一次才创建)
1 public sealed class singleton 2 { 3 private static singleton instance = null; 4 private static readonly object padlock = new object();//用于锁的使用 5 private singleton() 6 { 7 } 8 9 public static singleton instance 10 { 11 get 12 { 13 //双重锁定 (点线程里面 就不使用 lock,在性能上做了优化) 14 if (instance == null) 15 { 16 //将当前线程 锁住:造成 资源额外的开销,造成性能上的降低 (内部会进行 很多的处理) 17 lock (padlock) 18 { 19 if (instance == null) 20 { 21 instance = new singleton(); 22 } 23 } 24 } 25 return instance; 26 } 27 } 28 }
4.第四版本:静态初始化(饿汉模式)这就和.Net的框架挂钩,这是在.Net里面推荐的使用方式:代码简便并效率高
特点:
1、(*)“依赖”.Net Framwork 内部进行处理 变量的初始化。
2、对实例化的控制很少(大部分都是.Net内部实现的)
3、饿汉模式是“首先方法”
1 public sealed class Singleton 2 { 3 //静态只读的属性 4 private static readonly Singleton instance = null; 5 6 //静态构造函数:只要是在内存里面加载这个类(不管是实例化,还是调用这个类的静态成员)都会执行这个静态构造函数,并且不会消失 7 //保证了线程内唯一:因为只实例化一次 8 static Singleton() 9 { 10 instance = new Singleton(); 11 } 12 13 //私有构造函数:保证类不能被实例化 14 private Singleton() 15 { 16 } 17 18 //全局入口点 19 public static Singleton Instance 20 { 21 get 22 { 23 return instance; 24 } 25 } 26 27 }
上面的有一种问题,就是如果我的类里面如果有一个 静态方法SayHi(),在调用这个方法的时候,我不想将这个对象进行实例化,但是因为是静态构造函数,所以只要调用和这个类有关的对象都会调用静态构造函数,就会初始化实例化。解决方法:将静态初始化放到嵌套类里面。这样就不存在静态构造函数了,因为已经将他的静态初始化作用转移到了嵌套类里了。
5、最终版本:单例模式之饿汉模式 最终版(延迟初始化)
将初始化 的工作 交给了 嵌套类 Nested 的静态构造函数,所以 调用不想 初始化 对象 的 代码时 就不会执行
1 public sealed class Singleton 2 { 3 4 //不再使用静态构造函数 (但是他的 线程内唯一的 功能必须要实现) 5 //static Singleton() 6 //{ 7 8 //} 9 10 private Singleton() 11 { 12 13 } 14 15 public static Singleton Instance 16 { 17 get 18 { 19 return Nested.instance; 20 } 21 } 22 23 //调用这个方法的时候我并不想 调用 那个静态构造函数,对 其对象进行实例化 24 public static void SayHi() 25 { 26 Console.WriteLine("Hello"); 27 } 28 29 30 //解决上面的问题 使用静态类,通过这个静态 进行对 上面的那个类 进行 实例化 31 32 private class Nested 33 { 34 //注意这里不能是 private;因为那样的话 在外层类 里面就不能访问到了 35 internal static readonly Singleton instance = null; 36 37 //将 外层类的 静态构造函数的功能在 下面这个 静态构造函数实现了(线程内唯一) 38 static Nested() 39 { 40 instance = new Singleton(); 41 } 42 } 43 }