概述
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式在很多场景中都很常见,例如数据库连接池、日志记录器、配置管理器等,通过确保一个类只有一个实例,提高了代码的灵活性和可维护性。
结构
单例模式通常包含以下几个角色:
- 私有构造函数:防止外部实例化。
- 静态私有变量:用于存储单例实例。
- 公共静态方法:提供全局访问点,返回单例实例。
示例代码
单例模式有多种实现方式,下面列举了几种常见的变体:
代码地址
饿汉式(Eager Initialization)
饿汉式在类加载时就创建实例,线程安全,但如果实例未被使用会浪费资源。
public class EagerSingleton
{
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private EagerSingleton() { }
public static EagerSingleton Instance { get; } = new();
public void Log(string message)
{
Console.WriteLine($"EagerSingleton Log: {message}");
}
}
懒汉式(Lazy Initialization)
懒汉式在第一次使用时创建实例,非线程安全。
public class LazySingleton
{
private static LazySingleton? _instance;
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private LazySingleton() { }
public static LazySingleton Instance
{
get
{
return _instance ??= new LazySingleton();
}
}
public void Log(string message)
{
Console.WriteLine($"LazySingleton Log: {message}");
}
}
线程安全的懒汉式(Thread-Safe Lazy Initialization)
通过加锁实现线程安全,但性能较低。
public class ThreadSafeLazySingleton
{
private static ThreadSafeLazySingleton? _instance;
private static readonly object Lock = new();
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private ThreadSafeLazySingleton() { }
public static ThreadSafeLazySingleton Instance
{
get
{
lock (Lock)
{
_instance ??= new ThreadSafeLazySingleton();
}
return _instance;
}
}
public void Log(string message)
{
Console.WriteLine($"ThreadSafeLazySingleton Log: {message}");
}
}
双重检查锁定(Double-Check Locking)
在加锁前后都进行检查,减少加锁开销。
public class DoubleCheckLockingSingleton
{
private static DoubleCheckLockingSingleton? _instance;
private static readonly object Lock = new();
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private DoubleCheckLockingSingleton() { }
public static DoubleCheckLockingSingleton Instance
{
get
{
if (_instance != null)
{
return _instance;
}
lock (Lock)
{
_instance ??= new DoubleCheckLockingSingleton();
}
return _instance;
}
}
public void Log(string message)
{
Console.WriteLine($"DoubleCheckLockingSingleton Log: {message}");
}
}
静态内部类(Static Inner Class)
利用静态内部类的特性实现延迟加载和线程安全。
public class StaticInnerClassSingleton
{
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private StaticInnerClassSingleton() { }
private static class SingletonHolder
{
internal static readonly StaticInnerClassSingleton _instance = new();
}
public static StaticInnerClassSingleton Instance => SingletonHolder._instance;
public void Log(string message)
{
Console.WriteLine($"StaticInnerClassSingleton Log: {message}");
}
}
.NET中的Lazy实现
利用.NET中的Lazy
public class LazyTImplementationSingleton
{
private static readonly Lazy<LazyTImplementationSingleton> _instance = new(() => new LazyTImplementationSingleton());
/// <summary>
/// 私有构造函数,防止外部实例化
/// </summary>
private LazyTImplementationSingleton() { }
public static LazyTImplementationSingleton Instance => _instance.Value;
public void Log(string message)
{
Console.WriteLine($"LazyTImplementationSingleton Log: {message}");
}
}
应用场景
单例模式适用于以下场景:
- 当一个类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
优缺点
优点
- 控制实例数量:单例模式确保一个类只有一个实例,节省系统资源。
- 全局访问点:提供一个全局访问点,方便访问实例。
缺点
- 难以扩展:由于单例类不能被实例化多次,扩展单例类可能会比较困难。
- 隐藏依赖关系:单例模式可能会隐藏类之间的依赖关系,增加代码的复杂性。