设计模式学习之路——Singleton 单件模式

在程序设计过程中,有很多情况需要保证一个类只有一个实例.这时候就需要使用单件模式了。

保证一个类仅有一个实例,并提供一个该实例的全局访问点。——《设计模式》GoF

结构(Struct)

 

 

 

1 使用静态方法创建单件

让一个类只有一个实例,最容易的方法是在类中嵌入一个静态变量,并在第一个类实例中设置该变量,而且每次进入构造函数都要检查。不管类有多少个实例,静态变量只能有一个实例。为了防止类被多次实例化,我们把构造函数声明为私有的,这样只能在类的静态方法里创建一个实例。

单线程环境下Singleton模式的实现

 

代码
public class Singleton
    {
        
private static Singleton instance;
        
private Singleton() {}

        
public static Singleton Instance
        {
            
get 
            {
                
if (instance == null)
                {
                    instance 
= new Singleton();
                }
                
return instance;
            }
        }    
}

 

 

单线程Singleton模式的几个要点

1. Singleton模式中的实例构造器可以设置为protected以允许子类派生。

2. Singleton模式一般不要支持Icloneable接口,因为这可能导致多个对象实例,与Singleton模式的初衷违背。

3. Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。

4. Singleton模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来将,我们一般没有必要对其销毁进行特殊的管理。

5. 不能应对多线程环境:在多线程环境下,使用Singleton模式仍然有可能得到Singlet类的多个实例对象。

 

 

多线程环境下Singleton模式实现

 
代码
public class Singleton
    {
        
private static volatile Singleton instance;
        
private static object lockHelper = new object();

        
private Singleton() { }

        
public static Singleton Instance
        {
            
get
            {
                
if (instance == null)
                {
                    
lock (lockHelper)
                    {
                        
if (instance == null)
                        {
                            instance 
= new Singleton();
                        }
                    }
                }
                
return instance;
            }
        }
    }
代码
public class Singleton
    {
        
public static readonly Singleton Instance;

        
static Singleton()
        {
            Instance 
= new Singleton();
        }

        
private Singleton() { }

    }

上面的方式等同于下面的实现方式:

 

public class Singleton
    {
        
public static readonly Singleton Instance= new Singleton();
        
private Singleton() { }

    }

 

 

 

 

2 提供一个单件的全局访问点

由于使用单件可以提供一个类的全局访问点,即使C#中没有全局变量,设计程序时也必须为整个程序提供引用单件的方法。

一种解决方案是在程序的开头创建单件,并将其作为参数传递到需要使用它的类中。

 
     Singleton instance = Singleton.Instance;
     Test test
= new Test(instance);

 

 

这种方法的缺点是,在某次程序运行中,可能不需要所有的单件,,这样会影响程序的性能。

另一种更灵活的解决方案是,在程序中创建一个所有单件类的注册表,并使注册表始终是可用的,每次实例化一个单件,都将其记录在注册表中。程序的任何部分都能使用标识字符串访问任何一个单件实例,并能取回相应的实例变量。

注册表方法的缺点是减少了类型检查,因为注册表中的单件表可能把所有的单件都保存成对象类型,例如,hashtable中的对象类型,另外,注册表本身也有可能是一个单件,必须使用构造函数或者其他set函数把他传递给程序的所有部分。

提供一个全局访问点的最常用方式是使用类的静态方法。类名始终是可用的,静态方法只能由类调用,不能由类的实例调用,所以,不管程序中有多少个地方调用该方法,永远只能有一个这样的类实例。

原文地址:https://www.cnblogs.com/luoht/p/1750278.html