C#设计模式 之 单例模式
2023-09-11 14:20:51 时间
别名:单件模式、Singleton
一,意图
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
二,动机
在程序开发中,经常有这个样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率。
问题来了:
我们怎么才能保证一个类只有一个实例并且这个实例被容易的访问呢?
也许你一下就想到:定义一个全局变量使得这个实例被访问, 并且我保证在这个程序中我只实例化一次这个对象。 当然,我相信作为一个程序员你是可以做到这一点的。
请看下这句话:这应该是类的设计者的责任,而不是使用者的责任。
这就引出了单例设计模式:
让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问改实例的方法。
三,结构
- 单例 (Singleton) 类声明了一个名为 getInstance获取实例的静态方法来返回其所属类的一个相同实例。
- 单例的构造函数必须对客户端 (Client) 代码隐藏。 调用 获取实例方法必须是获取单例对象的唯一方式。
四,优缺点
优点:
- 可以派生:在单例类的实例构造器中可以设置以允许子类派生。
- 受控访问:因为单例类封装他的唯一实例,所以它可以严格的控制其他程序怎样以及何时访问它。
- 你获得了一个指向该实例的全局访问节点。
- 仅在首次请求单例对象时对其进行初始化。
缺点:
- 违反了单一职责原则。
- 单例模式一般不要支持序列化,因为这也有可能导致多个对象实例。
- 多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
五,应用场景
单例模式适合应用场景
如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。
单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。 该方法可以创建一个新对象, 但如果该对象已经被创建, 则返回已有的对象。
如果你需要更加严格地控制全局变量, 可以使用单例模式。
单例模式与全局变量不同, 它保证类只存在一个实例。 除了单例类自己以外, 无法通过任何方式替换缓存的实例。
- PS:你可以随时调整限制并设定生成单例实例的数量, 只需修改获取实例方法即可。
六,代码实现
实现方式:
- 在类中添加一个私有静态成员变量用于保存单例实例。
- 声明一个公有静态构建方法(属性)用于获取单例实例。
- 在静态方法(属性)中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。
- 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。
示例代码:
class Singleton
{
private static Singleton _instance; //1.
public static Singleton Instance //2.3.
{
get
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
private Singleton() { } // 4.
}
多线程单例
当使用多线程访问上述代码时,可能会导致被创建多个单例,修改代码如下,即可实现多线程下的单例:
思路:通过加锁保证同一时间只有一个线程访问构造
class SingletonThread
{
private static volatile SingletonThread _instance;
private static object lockHelper = new Object { };
public static SingletonThread Instance
{
get
{
// 双重校验,为避免额外的性能消耗
if(_instance== null)
{
// 当第一个线程运行到这里时,此时会对lock加锁,
// 当第二个线程运行该方法时,首先检测到lock加锁状态,该线程就会挂起等待第一个线程解锁
lock (lockHelper)
{
if(_instance== null)
{
_instance= new SingletonThread();
}
}
}
return _instance;
}
}
// 私有化构造
private SingletonThread() { }
}
volatile 关键字简介:传送门
另一种写法,利用静态构造器和只读属来制实现,(缺点:支持参数化构造)
.NET机制可控制静态构造器可以保证只有一个线程被执行
class SingletonRead {
// 只要访问就会被执行静态构造器,不使用不会进行实例化
public static readonly SingletonRead Instance = new Singleton_Read();
// 等价于
//public static readonly SingletonRead Instance;
//static SingletonRead ()
//{
// Instance = new SingletonRead ();
//}
private Singleton_Read(){}
}
设计模式系列博文示例代码工程:链接
相关文章
- C# Object对象的ToString方法在转换日期时丢失毫秒
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
- Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解
- C#订阅与发布标准实现 visual studio code .net 开发 设计模式之☞策略模式 C#字符串转二进制、二进制转字符串 c# 接口的协变和逆变 c# 使用迭代器来创建可枚举类型 博客园首页新随笔联系订阅管理 随笔 - 117 文章 - 0 评论 - 57 c# 创建,加载,修改XML文档
- C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路
- c#实例化继承类,必须对被继承类的程序集做引用 .net core Redis分布式缓存客户端实现逻辑分析及示例demo 数据库笔记之索引和事务 centos 7下安装python 3.6笔记 你大波哥~ C#开源框架(转载) JSON C# Class Generator ---由json字符串生成C#实体类的工具
- C# Json反序列化 C# 实现表单的自动化测试<通过程序控制一个网页> 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案) 大话设计模式:原型模式 C# 深浅复制 MemberwiseClone
- 装饰者模式的学习(c#) EF SaveChanges() 报错(转载) C# 四舍五入 保留两位小数(转载) DataGridView样式生成器使用说明 MSSQL如何将查询结果拼接成字符串 快递查询 C# 通过smtp直接发送邮件 C# 带参访问接口,WebClient方式 C# 发送手机短信 文件 日志 写入 与读取
- 浅谈c#的三个高级参数ref out 和Params C#中is与as的区别分析 “登陆”与“登录”有何区别 经典SQL语句大全(绝对的经典)
- C# 单例模式和窗体的单例打开方法
- C#,字符串匹配(模式搜索)KMP算法的源代码与数据可视化
- 总结一下C#中深拷贝的几种方法
- c#利用宏定义调试代码
- C#设计模式(1)——单例模式
- 《敏捷软件开发:原则、模式与实践(C#版.修订版)》一第2章 极限编程概述
- C#去除小数位右边无用的0
- C#控件datagridview的表头填入tag对象,再获取出来
- c# 普通打印机大致有三种方法(非热敏打印机及lpt1并口指令控制型)
- C# WinForm 窗体单例模式
- 【设计模式】C#设计模式:单例模式
- 【设计模式】C#设计模式:原型模式
- C#下 观察者模式的另一种实现方式IChangeToken和ChangeToken.OnChange
- C#的StackExchange.Redis实现订阅分发模式
- C#基础 Math Pow Sqrt 幂与平方根