当前位置: 首页 > news >正文

41、C#什么是单例设计模式

单例设计模式(Singleton Pattern) 是一种创建型设计模式,它的核心目标是:

确保一个类在整个应用程序生命周期中,有且仅有一个实例,并提供一个全局访问点。


✅ 为什么需要单例?

有些对象天然只需要一个,比如:

  • 日志记录器(Logger)
  • 配置管理器(ConfigManager)
  • 数据库连接池
  • 线程池
  • 应用程序的主窗口(某些桌面应用)

如果允许多个实例:

  • 可能导致资源浪费(如重复读取配置文件)
  • 引发状态不一致(如多个 Logger 写同一个文件冲突)
  • 违反业务逻辑(如“系统设置”只能有一份)

👉 单例就是为了解决这些问题。


✅ 单例的核心要素

要实现真正的单例,必须满足 3 个条件

  1. 私有构造函数 → 防止外部 new
  2. 静态私有字段 → 保存唯一实例
  3. 公共静态属性/方法 → 提供全局访问点

✅ C# 中的单例实现方式(从简单到线程安全)

方式 1️⃣:懒汉式(Lazy,非线程安全)—— ❌ 不推荐

public class Singleton
{private static Singleton _instance;private Singleton() { } // 私有构造函数public static Singleton Instance{get{if (_instance == null)_instance = new Singleton();return _instance;}}
}

⚠️ 问题:多线程下可能创建多个实例!


方式 2️⃣:饿汉式(Eager)—— ✅ 简单安全,但可能浪费资源

public class Singleton
{private static readonly Singleton _instance = new Singleton();private Singleton() { }public static Singleton Instance => _instance;
}

优点:线程安全(静态字段在类型加载时初始化)
缺点:即使不用也会创建实例(不支持懒加载)


方式 3️⃣:双重检查锁(Double-Checked Locking)—— ✅ 经典线程安全

public class Singleton
{private static volatile Singleton _instance;private static readonly object _lock = new object();private Singleton() { }public static Singleton Instance{get{if (_instance == null) // 第一次检查{lock (_lock){if (_instance == null) // 第二次检查_instance = new Singleton();}}return _instance;}}
}

优点:线程安全 + 懒加载
⚠️ 注意:必须加 volatile 防止指令重排序(.NET 中有时可省略,但建议保留)


方式 4️⃣:推荐!使用 Lazy<T>(C# 4+)—— ✅ 最简洁安全

public class Singleton
{private static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(() => new Singleton());private Singleton() { }public static Singleton Instance => _instance.Value;
}

优点

  • 线程安全(Lazy<T> 内部已处理)
  • 懒加载
  • 代码简洁
  • 支持异常处理和自定义初始化逻辑

⚠️ 单例的常见陷阱

问题说明
反射破坏通过反射可调用私有构造函数 → 可加 if (_instance != null) throw 防御
序列化破坏反序列化可能创建新实例 → 实现 ISerializable 或使用 [NonSerialized]
多线程安全必须确保初始化过程线程安全(见上文)
单元测试困难全局状态难以 mock → 可考虑依赖注入替代

🆚 单例 vs 静态类

特性单例静态类
可继承/实现接口✅ 可以❌ 不可以
延迟初始化✅ 可以❌ 静态字段在类型加载时初始化
支持多态✅ 可以❌ 不行
单元测试友好度中等(可通过接口解耦)差(无法 mock)
内存位置托管堆静态区

💡 如果你只需要工具方法(无状态),用静态类
如果你需要状态 + 全局唯一 + 可扩展,用单例


✅ 现代替代方案:依赖注入(DI)

在 ASP.NET Core 等现代框架中,更推荐用 DI 容器注册单例,而非手写单例:

// 注册
services.AddSingleton<ILogger, FileLogger>();// 使用(通过构造函数注入)
public class MyService
{private readonly ILogger _logger;public MyService(ILogger logger) => _logger = logger;
}

优势

  • 解耦
  • 易于测试
  • 生命周期由容器管理
  • 避免全局状态污染

📌 建议:在新项目中优先考虑 DI,仅在无法使用 DI 的场景(如旧系统、工具类库)使用传统单例。


✅ 小结

关键点说明
目的确保全局只有一个实例
三要素私有构造函数 + 静态实例 + 全局访问点
推荐实现Lazy<T> 或 DI 容器
慎用场景避免滥用(不是所有“全局”都需要单例)

🧠 一句话记住
“单例 = 全局唯一实例,懒加载 + 线程安全是关键。”


问题

什么是全局状态

它是可以从应用程序任何位置访问的状态

为什么单例是一种反模式

因为它是一部分全局状态,而全局状态很难控制。

单例设计模式和应用程序单例有什么区别

应用程序单例只是在应用程序各处使用的单一对象,他不会强制其单例性,而单例设计模式会。

http://www.dtcms.com/a/618740.html

相关文章:

  • kafka单机版安装
  • 网站开发要求有哪些大沥南庄网站建设
  • 我在高职教STM32(新12)——STM32中断概览
  • OceanBase 内存数据转储、合并说明
  • 网站开发设计制作公司微信软文案例
  • 下载安装pycharm 并通过pycahrm来驱动Anaconda来运行Python程序
  • dw网站建设讨论总结wordpress的程序文件
  • Kratos微服务框架下实现CQRS架构模式
  • openGauss实战:Python开发与AI向量数据库应用
  • 第43节:集群渲染:分治策略处理超大规模场景
  • php的数组和python的列表 -- 横向对比学习
  • 队列传输的函数应用原理(拷贝原理)
  • 工商局网站开发费用高速公路建设管理局网站
  • redis的启动方式
  • 电子商务基础网站建设与维护单项选择题wordpress 移动端 域名
  • docker启动redis
  • 热点数据自动缓存方案:基于京东 Hotkey 实践
  • 软件著作权可以在哪些方面使用?
  • 【复习】计网每日一题1116大题--MAC帧、IPv4数据报、TVP报文段首部格式-------待补充
  • RF层原理与传输特性介绍
  • 企业网站建设合同应注意什么网站建设工资多少钱
  • YAML配置文件 对缩进非常敏感,错误的缩进会导致解析失败。
  • gca() got an unexpected keyword argument ‘projection‘
  • 网站收录查询爱站律所网站建设国队男子接力赛
  • 单片机/嵌入式修行之路
  • GitHub 热榜项目 - 日榜(2025-11-16)
  • 车联网安全:调试接口安全测试.
  • 人工智能技术- 语音语言- 04 GPT-4 参加专业考试
  • 产品网站开发流程图网站建设get你
  • 从零开始造轮子:用C++实现大语言模型推理的核心逻辑