在某些情况下 , 特定类型的数据需要提供给应用程序中的其他所有对象使用。在大多数情况下,这种类型的数据在系统中还是唯一的。
如何使对象实例全局可用,并保证仅创建一个此类的实例?
Singleton 通过下列方法提供唯一的全局实例:
? 1.让类创建自己的唯一实例。
? 2.允许其他对象通过可返回实例引用的类方法来访问此实例。类方法是全局可访问的。?
? 3.将类构造函数声明为私有,从而任何其他对象都不能创建新实例。
下而是C#实现Singleton模式的代码:
?? private Singleton {
?? }
?? public static Singleton Instance {
????? get {
???????? if ( instance == null ) instance = new Single();
???????? return instance;
????? }
?? }
?? private static Singleton instance;
} // class Singleton
该实现主要有两个优点:
1.由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。
2.直到对象要求产生一个实例才执行实例化;这种方法称为"懒实例化"。懒实例化避免了在应用程序启动时实例化不必要的 singleton。
但是,这种实现的主要缺点是在多线程环境下它是不安全的。如果执行过程的不同线程同时进入 Instance 属性方法,那么可能会创建多个 Singleton 对象实例。
解决此问题的方法有很多。一种方法是使用被称为 Double-Check Locking [Lea99] 的技术。而 C# 与公共语言运行库也提供了一种"静态初始化"方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决这些问题。
静态初始化
?? private Singleton() {
?? }
?? private static Singleton Instance {
????? get { return instance; }
???}
?? private static readonly Singleton instance = new Singleton();
} //class Singleton
在此策略中,将在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化。该类标记为 sealed 以阻止发生派生,而派生可能会增加实例。此外,变量标记为 readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。
该实现与前面的示例类似,不同之处在于它依赖公共语言运行库来初始化变量。它仍然可以用来解决 Singleton 模式试图解决的两个基本问题:全局访问和实例化控制。公共静态属性为访问实例提供了一个全局访问点。此外,由于构造函数是私有的,因此不能在类本身以外实例化 Singleton 类;因此,变量引用的是可以在系统中存在的唯一的实例。
由于 Singleton 实例被私有静态成员变量引用,因此在类首次被对 Instance 属性的调用所引用之前,不会发生实例化。
这种方法唯一的潜在缺点是,您对实例化机制的控制权较少。在 Design Patterns 形式中,您能够在实例化之前使用非默认的构造函数或执行其他任务。由于在此解决方案中由 .NET Framework 负责执行初始化,因此您没有这些选项。在大多数情况下,静态初始化是在 .NET 中实现 Singleton 的首选方法。
多线程 Singleton
静态初始化适合于大多数情形。如果您的应用程序必须延迟实例化、在实例化之前使用非默认的构造函数或执行其他任务、并且工作在多线程环境中,那么您需要另一种解决方案。但是,在一些情况下,您无法像在"静态初始化"示例中那样依赖公共语言运行库来确保线程的安全性。在这种情况下,必须使用特定的语言功能来确保在存在多线程的情况下仅创建一个对象实例。更常见的解决方案之一是使用 Double-Check Locking [Lea99] 技术来阻止不同的线程同时创建 singleton 的新实例。
下面的实现仅允许一个线程在尚未创建 Singleton 实例的情况下进入关键区域(该区域由 lock 块标识)。
?? private Singleton() {
?? }
?? public static Singleton Instance {
????? get {
???????? if ( instance == null ) {
??????????? lock( syncRoot ) {
?????????????? if ( instance == null ) instance = new Singleton();
??????????? }
???????? }
???????? return instance;
??????}
?? }
?? private static volatile Singleton instance;
?? private static object syncRoot = new object();
} //class Singleton
此方法确保了仅在需要实例时才会创建仅一个实例。此外,变量被声明为 volatile,以确保只有在实例变量分配完成后才能访问实例变量。最后,此方法使用 syncRoot 实例来进行锁定(而不是锁定类型本身,具体原因请参考切忽锁定类形对象),以避免发生死锁。
此 double-check locking 方法解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下,静态初始化方法已经够用。
-- 摘自MSDN? 《使用Microsoft .NET的企业解决方案模式》一文中的Singleton模式