单例模式的实现

先上示例

复制代码
public class DeviceManager
{

    private readonly Dictionary<string, Device> _devices;

    private DeviceManager()
    {
        _devices = new Dictionary<string, Device>();
    }

    public static DeviceManager Instance { get; } = new DeviceManager();    // { get; } 只读,外部不可对Instance做修改
    //也可能不叫Instance , Shared ,Default

    public void AddDevice(Device device)
    {
        if (device == null)
        {
            throw new ArgumentNullException(nameof(device));    //nameof(device)获取变量名
        }

        if (_devices.ContainsKey(device.Name))
        {
            throw new ArgumentException("Device with the same name already exists.");
        }

        lock (_devices)
        {
            _devices.Add(device.Name, device);
        }
    }

    public Device GetDevice(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }

        lock (_devices)
        {
            _devices.TryGetValue(name, out var device);
            return device;
        }           
    }
}

public class Device
{
    public string Name { get; internal set; }
}

代码调用

复制代码
try
{
    DeviceManager.Instance.AddDevice(new Device { Name = "Device1" });
    var device = DeviceManager.Instance.GetDevice("Device1");
    Console.WriteLine(device.Name) ;

    Console.ReadKey();
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

为什么要使用单例模式?

线程安全:在需要多线程环境下使用时,单例模式可以提供线程安全的访问控件。DeviceManager.Instance 是静态属性,有.Net Framework在程序加载时进行初始化,确保了多线程下的安全范围

为什么会有线程安全问题:在多线程环境中,需确保数据和资源的安全访问,因为多个线程同时操作共享的数据可能会导致数据不一致的行为。

为什么单例能保证线程安全:在下面例子中,静态属性DeviceManage.Instance 是在 程序加载时 初始化的,且只会 初始化一次,确保软件整个生命周期内,只有一个 DeviceManage.Instance 实例存在

保证线程安全的方式:

1.静态属性的初始化是由 CLR(Common Language Runtime) 保证的, CLR会在第一次访问静态属性时进行初始化, 并且会阻止多个线程同时进行初始化操作,避免竞态条件。

2.互斥访问:DeviceManger 类的方法,字段和构造器都是私有的,因此外部无法直接修改_device字典,内部方法又是可控的(可以通过Lock),这样可以避免多个线程同时修改_Device 引起并发问题

3.线程同步:如果 DeviceManager 类中存在需要多线程访问和修改的共享资源,可以使用线程同步机制来确保安全访问,比如使用 lock 关键字或者 Monitor 类来保护关键代码段,防止多线程竞争条件的发生。

此外单例模式的优点:全局访问、资源共享、避免重复实例化、单一职责

适用单例的场景

1.全局状态(配置文件读取,系统设置)或配置

2.资源管理 (数据库连接池,文件系统管理器,线程池)

3.日志记录 日志记录器

4.缓存管理 缓存系统通常需要统一管理,以便在不同部分的应用程序中共享数据。

5.设备连接管理 管理外部设备(打印机,传感器)或网络连接时,需要确保系统中只有一个控制器实例来管理设备的通讯或连接

6.服务定位器

不适用单例的场景

  1. 多线程问题: 当单例模式未正确实现时

  2. 测试和依赖注入: 需了解**

  3. 单例可能会增加耦合性

相关推荐
慧一居士1 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
花间相见1 小时前
【LangChain组件03】—— LangChain Agents 执行与状态:工作流程与状态管理实战
java·前端·langchain
kyriewen2 小时前
面试官让我用 AI 重构一个 8 年陈的 React 组件——他说他不看代码,只看我会不会拆
前端·javascript·面试
计算机魔术师2 小时前
700吉瓦「幽灵用电」:美国AI数据中心的抢电闹剧正在失控
前端
IT_陈寒2 小时前
JavaScript数组排序踩的坑,差点让我加班到凌晨
前端·人工智能·后端
风骏时光牛马2 小时前
提示词工程:大模型交互的核心构建艺术
前端
今日无bug2 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent
计算机魔术师2 小时前
Anthropic 复盘 Claude 模型越权访问真实系统事件并改进对齐与安全措施
前端
掘金者阿豪3 小时前
Seedance 2.0/2.5 虚拟素材能跨 Key 共用吗?一次讲清 Asset ID、账号隔离与 SaaS 素材架构
前端·后端
Jacky19993 小时前
Electron + Vue 3 桌面打字游戏实战:从 VSCode 扩展到独立应用的架构改造
javascript