C#单例模式的几种实现方式
程序员文章站
2022-07-14 08:40:28
...
单例模式
-
动机(Motivation)
- 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
- 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
- 这应该是类设计者的责任,而不是使用者的责任
-
意图(Intent)
- 保证一个类仅有一个实例,并提供一个该实例的全局访问点。——《设计模式》GoF
简单实现
public sealed class Singleton
{
private static Singleton _instance = null;
private Singleton()
{
}
public static Singleton Instance
{
get { return _instance ?? (_instance = new Singleton()); }
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
说明:
- 对于线程来说不安全
- 单线程中已满足要求
- 优点:
- 由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能
- 直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的 singleton。
线程安全的
public sealed class Singleton
{
private static Singleton _instance = null;
private static readonly object Padlock = new object();
private Singleton()
{
}
public static Singleton Instance
{
get
{
lock (Padlock)
{
if (_instance == null)
{
_instance = new Singleton();
}
}
return _instance;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
说明:
- 同一个时刻加了锁的那部分程序只有一个线程可以进入
- 对象实例由最先进入的那个线程创建
- 后来的线程在进入时(instence == null)为假,不会再去创建对象实例
- 增加了额外的开销,损失了性能
双重锁定
public sealed class Singleton
{
private static Singleton _instance = null;
private static readonly object Padlock = new object();
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (_instance == null)
{
lock (Padlock)
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
说明:
- 多线程安全
- 线程不是每次都加锁
- 允许实例化延迟到第一次访问对象时发生
静态初始化
public sealed class Singleton
{
private static readonly Singleton _instance = null;
static Singleton()
{
_instance = new Singleton();
}
private Singleton()
{
}
public static Singleton Instance
{
get
{
return _instance;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
说明:
- 依赖公共语言运行库负责处理变量初始化
- 公共静态属性为访问实例提供了一个全局访问点
- 对实例化机制的控制权较少(.NET代为实现)
- 静态初始化是在 .NET 中实现 Singleton 的首选方法
延迟初始化
public sealed class Singleton
{
private Singleton()
{
}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
private class Nested
{
internal static readonly Singleton instance = null;
static Nested()
{
instance = new Singleton();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
说明:
- 初始化工作由Nested类的一个静态成员来完成,这样就实现了延迟初始化
注意事项
- Singleton模式中的实例构造器可以设置为protected以允许子类派生。
- Singleton模式一般不要支持ICloneable接口,因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
- Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。
- Singletom模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来讲,我们一般没有必要对其销 毁进行特殊的管理。
总结
- Singleton模式是限制而不是改进类的创建。
- 理解和扩展Singleton模式的核心是“如何控制用户使用new对一个类的构造器的任意调用”。
- 可以很简单的修改一个Singleton,使它有少数几个实例,这样做是允许的而且是有意义的。