C# 设计模式——单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是设计模式中最基础但应用最广泛的一种模式,它确保一个类只有一个实例,并提供一个全局访问点。在C#开发中,单例模式常用于管理共享资源、配置管理、日志系统等场景。
·
单例模式(Singleton Pattern)是设计模式中最基础但应用最广泛的一种模式,它确保一个类只有一个实例,并提供一个全局访问点。在C#开发中,单例模式常用于管理共享资源、配置管理、日志系统等场景。
文章目录
一、基础实现:线程不安全的单例
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. 最佳实践
- 优先使用Lazy:简洁、安全、高效
- 避免全局状态:单例应尽量无状态或只读状态
- 考虑依赖注入:使用DI容器管理生命周期
- 谨慎使用:单例模式容易滥用,确保真正需要全局唯一实例
- 单元测试友好:通过接口抽象,便于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#开发中不可或缺的设计模式,但需要谨慎使用:
- 优先选择Lazy实现:安全、高效、简洁
- 考虑线程安全和生命周期管理:避免内存泄漏和并发问题
- 结合依赖注入使用:提高可测试性和灵活性
- 避免滥用:只在真正需要全局唯一实例时使用
“单例模式就像一把双刃剑——用得好能简化架构,用不好会制造麻烦。理解其原理和应用场景,才能发挥它的真正价值。”
更多推荐
所有评论(0)