.Net设计模式之单例模式

您所在的位置:网站首页 列举一个单例模式 .Net设计模式之单例模式

.Net设计模式之单例模式

2024-07-15 20:40| 来源: 网络整理| 查看: 265

单例模式的介绍

在软件的开发过程中,很多时候,我们需要对一个类进行实例化后,再使用,有时这个类比较简单,有时也可能会很复杂,但不管怎样,为了保证软件的质量和效率,大多数时候,我们只希望它被实例化一次,所以这就需要引入单例模式(Singleton Pattern)了。单例模式,即保证一个类仅有一个实例,并提供一个访问它的全局访问点。那,怎么做到呢?为不不被实例化多个对象,就可以让类自身负责保存它的唯一实例。软件中重复使用某个类时,为了防止多次实例化产生的资源消耗,这个时候就应该使用单例设计模式了。如:网络请求、数据库操作等。

上面为单例的类图

单例要点 构造函数不对外开放,一般为 private; 通过一个静态方法或者枚举返回单例对象; 确保单例类的对象有且只有一个,尤其是在多线程环境下; 确保单例类对象在反序列化时不会被重新构建对象。 代码示例 简单实现 public class Singleton { private static Singleton instance; /// /// 构造方法为private,可以僻免外界通过利用new创建此类实例的可能 /// private Singleton() { } /// /// 此方法为获得本类实例的唯一全局访问点 /// /// public static Singleton GetInstance() { if (instance == null) { return instance; } return instance; } }

上面的写法,可以实现单例模式,在单线程的情况下,并没有问题,但如果在多线程的环境下,两个或更多的线程同时判断 instance == null 为 true, 那么这个类仍然可以被多次实例化,那么它是不安全的,并不是真正的单例。这个时候,我们就会想到,可以在这之前,加上 lock 解决问题。提示代码如下:

线程安全 public class Singleton { private static readonly object locker = new object(); private static Singleton instance; /// /// 构造方法为private,可以僻免外界通过利用new创建此类实例的可能 /// //private Singleton() { } /// /// 此方法为获得本类实例的唯一全局访问点 /// /// public static Singleton GetInstance() { lock (locker) { if (instance == null) { return instance; } } return instance; } } lock( locker) // 在同一时刻加了锁的那部分程序,只有一个线程可以进入,其他线程要进入,只能待已进行的线程退出lock程序块后,才能进入,这就保证了线程安全,不会创建多个实例。现在线程安全是解决了,但还是有个小问题,每次获取实例的时候,都需要加锁,然后才能判断实例是否被创建了,怎么解决这个问题?这就需要再引入一个 双重锁 的做法了。 双重锁定 /// /// /// public class Singleton { private static readonly object locker = new object(); private static Singleton instance; /// /// 构造方法为private,可以僻免外界通过利用new创建此类实例的可能 /// //private Singleton() { } /// /// 此方法为获得本类实例的唯一全局访问点 /// /// public static Singleton GetInstance() { // 判断1 if (instance == null) { lock (locker) { // 判断2 if (instance == null) { return instance; } } } return instance; } }

上面的代码,在lock(locker) 前后,都加入了 对实例是否创建的判断, 判断1 主要是考虑到在实例已经被创建后,僻免程序再锁定 后面的程序块,减少资源的浪费,判断2 是为了 在没有创建实例的情况下才创建实例。经过多次改造后的单例,看似完美,但还是在获取实例的时候需要去判断实例是不是被创建了,那么,有没有别的方式每次都去判断呢?答案是有的,C#与公共语言运行库也提供了一种 "静态初始化" 方法,这种方法不需要开发人员显式地编写线程安全代码。

静态初始化 /// /// 这里用到了 sealed 主要是不让其他类继承,而继承可能会增加实例 /// public sealed class Singleton { //在第一次引用类的任何成员时创建实例,由公共语言运行库负责处理变量的初始化 private static readonly Singleton instance = new Singleton(); //构造函数私有化,是为了不被通过 new 达到实例化的目的 private Singleton() { } public static Singleton GetSingleton() { return instance; } }

这个实现方式与前面的示例类似,都是解决了单例模式试图解决的两个基本问题:全局访问和实例化控制,公共静态属性是为访问实例提供了一个全局访问点。不同的地方在于它依赖公共语言运行库来初始化变量。再就是它的构造方法标记为私有,所以不能在类本身以外的地方通过 new 来实例化 Singleton 类;因此变量引用的是可以在系统中存在唯一的实例。值得注意的是,instance 变量标记为 readonly,也就是只能在静态初始化期间 或 在类的构造函数中分配变量。关于 sealed 的关键字,也可以在上面几个类中使用,只是类可能要稍加改动。

最后,感觉各位能花时间看到这里,谢谢,欢迎留言交流。

参考文献:

大话设计模式 程杰 著



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3