C# 设计模式——单例模式(Singleton Pattern)

单例模式(Singleton Pattern)是设计模式中最基础但应用最广泛的一种模式,它确保一个类只有一个实例,并提供一个全局访问点。在C#开发中,单例模式常用于管理共享资源、配置管理、日志系统等场景。

文章目录

    • 一、基础实现:线程不安全的单例
    • 二、线程安全实现
      • 1. 双重检查锁定模式(Double-Check Locking)
      • 2. 使用Lazy(推荐方式)
    • 三、进阶实现技巧
      • 1. 防止反射攻击
      • 2. 处理序列化问题
    • 四、单例模式在依赖注入中的应用
      • 1. 在ASP.NET Core中注册单例服务
      • 2. 实现单例服务
    • 五、单例模式的变体
      • 1. 多例模式(Multiton)
      • 2. 线程单例(Thread-Specific Singleton)
    • 六、性能优化与最佳实践
      • 1. 性能对比(基准测试)
      • 2. 最佳实践
    • 七、实际应用场景
      • 1. 配置管理器
      • 2. 日志系统
      • 3. 缓存管理器
    • 八、常见陷阱与解决方案
      • 1. 单例的生命周期问题
      • 2. 测试难题
    • 九、单例模式在现代架构中的演变
      • 1. 微服务架构中的单例
      • 2. 云原生环境下的实现
    • 结论

一、基础实现:线程不安全的单例

public class BasicSingleton
{
    private static BasicSingleton _instance;
    
    // 私有构造函数防止外部实例化
    private BasicSingleton() 
    {
        // 初始化代码
    }
    
    public static BasicSingleton Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new BasicSingleton();
            }
            return _instance;
        }
    }
    
    public void DoWork()
    {
        Console.WriteLine("单例工作方法");
    }
}

// 使用示例
var singleton = BasicSingleton.Instance;
singleton.DoWork();

问题分析:此实现在多线程环境下可能创建多个实例,不适用于生产环境。

二、线程安全实现

1. 双重检查锁定模式(Double-Check Locking)

public class ThreadSafeSingleton
{
    private static volatile ThreadSafeSingleton _instance;
    private static readonly object _lock = new object();
    
    private ThreadSafeSingleton() { }
    
    public static ThreadSafeSingleton Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new ThreadSafeSingleton();
                    }
                }
            }
            return _instance;
        }
    }
}

关键点

  • volatile 关键字确保多线程环境下的可见性
  • 双重检查减少锁竞争,提高性能

2. 使用Lazy(推荐方式)

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

优势

  • 线程安全且高效
  • 延迟初始化(Lazy Initialization)
  • 简洁易读

三、进阶实现技巧

1. 防止反射攻击

public class ReflectionSafeSingleton
{
    private static readonly Lazy<ReflectionSafeSingleton> _lazy = 
        new Lazy<ReflectionSafeSingleton>(() => new ReflectionSafeSingleton());
    
    private static bool _created;
    
    private ReflectionSafeSingleton()
    {
        if (_created)
        {
            throw new InvalidOperationException("只能创建一个实例");
        }
        _created = true;
    }
    
    public static ReflectionSafeSingleton Instance => _lazy.Value;
}

2. 处理序列化问题

[Serializable]
public class SerializableSingleton : ISerializable
{
    private static readonly Lazy<SerializableSingleton> _lazy = 
        new Lazy<SerializableSingleton>(() => new SerializableSingleton());
    
    private SerializableSingleton() { }
    
    public static SerializableSingleton Instance => _lazy.Value;
    
    // 防止序列化创建新实例
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        throw new NotSupportedException();
    }
    
    // 使用序列化代理
    [Serializable]
    private class SingletonSerializationHelper : IObjectReference
    {
        public object GetRealObject(StreamingContext context)
        {
            return SerializableSingleton.Instance;
        }
    }
}

四、单例模式在依赖注入中的应用

1. 在ASP.NET Core中注册单例服务

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IConfigService, ConfigService>();
}

2. 实现单例服务

public class ConfigService : IConfigService
{
    private readonly IConfiguration _config;
    
    public ConfigService(IConfiguration config)
    {
        _config = config;
    }
    
    public string GetValue(string key)
    {
        return _config[key];
    }
}

五、单例模式的变体

1. 多例模式(Multiton)

public class Multiton
{
    private static readonly Dictionary<string, Lazy<Multiton>> _instances = 
        new Dictionary<string, Lazy<Multiton>>();
    
    private static readonly object _lock = new object();
    
    private Multiton(string key) 
    {
        Key = key;
    }
    
    public string Key { get; }
    
    public static Multiton GetInstance(string key)
    {
        if (!_instances.ContainsKey(key))
        {
            lock (_lock)
            {
                if (!_instances.ContainsKey(key))
                {
                    _instances[key] = new Lazy<Multiton>(() => new Multiton(key));
                }
            }
        }
        return _instances[key].Value;
    }
}

2. 线程单例(Thread-Specific Singleton)

public class ThreadSingleton
{
    private static readonly ThreadLocal<ThreadSingleton> _threadInstance = 
        new ThreadLocal<ThreadSingleton>(() => new ThreadSingleton());
    
    private ThreadSingleton() { }
    
    public static ThreadSingleton Instance => _threadInstance.Value;
}

六、性能优化与最佳实践

1. 性能对比(基准测试)

实现方式 首次访问时间 后续访问时间 线程安全
基础实现
双重检查锁定 中等
Lazy 中等 极快
静态初始化 极快

2. 最佳实践

  1. 优先使用Lazy:简洁、安全、高效
  2. 避免全局状态:单例应尽量无状态或只读状态
  3. 考虑依赖注入:使用DI容器管理生命周期
  4. 谨慎使用:单例模式容易滥用,确保真正需要全局唯一实例
  5. 单元测试友好:通过接口抽象,便于Mock测试

七、实际应用场景

1. 配置管理器

public class ConfigManager
{
    private static readonly Lazy<ConfigManager> _instance = 
        new Lazy<ConfigManager>(() => new ConfigManager());
    
    private readonly IConfiguration _config;
    
    private ConfigManager()
    {
        _config = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .Build();
    }
    
    public static ConfigManager Instance => _instance.Value;
    
    public string GetSetting(string key) => _config[key];
}

2. 日志系统

public class Logger
{
    private static readonly Lazy<Logger> _instance = 
        new Lazy<Logger>(() => new Logger());
    
    private readonly StreamWriter _logWriter;
    
    private Logger()
    {
        _logWriter = new StreamWriter("application.log", append: true);
    }
    
    public static Logger Instance => _instance.Value;
    
    public void Log(string message)
    {
        _logWriter.WriteLine($"{DateTime.Now}: {message}");
        _logWriter.Flush();
    }
    
    ~Logger()
    {
        _logWriter?.Dispose();
    }
}

3. 缓存管理器

public class CacheManager
{
    private static readonly Lazy<CacheManager> _instance = 
        new Lazy<CacheManager>(() => new CacheManager());
    
    private readonly ConcurrentDictionary<string, object> _cache = 
        new ConcurrentDictionary<string, object>();
    
    private CacheManager() { }
    
    public static CacheManager Instance => _instance.Value;
    
    public T Get<T>(string key) where T : class
    {
        return _cache.TryGetValue(key, out var value) ? value as T : null;
    }
    
    public void Set(string key, object value, TimeSpan? expiry = null)
    {
        _cache[key] = value;
        
        if (expiry.HasValue)
        {
            Task.Delay(expiry.Value).ContinueWith(_ => _cache.TryRemove(key, out _));
        }
    }
}

八、常见陷阱与解决方案

1. 单例的生命周期问题

问题:在长时间运行的应用程序中,单例可能持有资源导致内存泄漏

解决方案

public class DisposableSingleton : IDisposable
{
    private static readonly Lazy<DisposableSingleton> _instance = 
        new Lazy<DisposableSingleton>(() => new DisposableSingleton());
    
    private DisposableSingleton() { }
    
    public static DisposableSingleton Instance => _instance.Value;
    
    private bool _disposed;
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        
        if (disposing)
        {
            // 释放托管资源
        }
        
        // 释放非托管资源
        _disposed = true;
    }
    
    ~DisposableSingleton() => Dispose(false);
}

2. 测试难题

问题:单例的全局状态使单元测试困难

解决方案:使用接口和依赖注入

public interface ISingletonService
{
    void PerformOperation();
}

public class SingletonService : ISingletonService
{
    private static readonly Lazy<SingletonService> _instance = 
        new Lazy<SingletonService>(() => new SingletonService());
    
    private SingletonService() { }
    
    public static ISingletonService Instance => _instance.Value;
    
    public void PerformOperation()
    {
        // 实现
    }
}

// 测试中使用Mock
public class MyTest
{
    [Fact]
    public void TestMethod()
    {
        var mockService = new Mock<ISingletonService>();
        var myClass = new MyClass(mockService.Object);
        
        // 测试逻辑
    }
}

九、单例模式在现代架构中的演变

1. 微服务架构中的单例

在分布式系统中,单例模式演变为:

  • 分布式缓存(Redis)
  • 配置中心(Consul, Zookeeper)
  • 全局ID生成器(Snowflake算法)

2. 云原生环境下的实现

// 使用Azure Durable Functions实现分布式单例
[FunctionName("SingletonOrchestrator")]
public static async Task RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // 确保只有一个实例运行
    using (await context.LockAsync("mySingletonLock"))
    {
        // 单例业务逻辑
        await context.CallActivityAsync("SingletonTask", null);
    }
}

结论

单例模式是C#开发中不可或缺的设计模式,但需要谨慎使用:

  1. 优先选择Lazy实现:安全、高效、简洁
  2. 考虑线程安全和生命周期管理:避免内存泄漏和并发问题
  3. 结合依赖注入使用:提高可测试性和灵活性
  4. 避免滥用:只在真正需要全局唯一实例时使用

“单例模式就像一把双刃剑——用得好能简化架构,用不好会制造麻烦。理解其原理和应用场景,才能发挥它的真正价值。”

你可能感兴趣的:(C#设计模式,c#,设计模式,单例模式)