学习笔记[1]——Singleton(单件)模式

1 概述

        单件模式用来创造独一无二的,只有一个实例的对象入场券。在软件开发中,有时需要这样的特殊实例,比如一个线程池(threadpool)、一个缓存(cache)、一个日志对象、一个虚拟打印机等。单件模式就是针对上述问题而产生的,它保证一个类仅有一个实例,并提供一个它的全局访问点。

        当然,保证仅有一个实例还有其他办法,比如程序员之间的约定或者是提供一个静态的全局变量。但是,这两个方法都是不安全的!约定不能保证人人都记得这个规则,特别对于分布式开发。而静态的全局变量,也不能阻止人们使用new来创建一个新对象。

     所以,单件模式提供的类创建机制必须实现以下两个功能:(1)要把实例的产生从“类的使用者”手里拿过来,即在“类的创建者”中完成;(2)要禁止外部使用new关键字来创建类的实例;

2 分析实现

        为了完成上面的目标,我们应该在类自身完成类的创建。此外,为了禁止外部使用new来实例化类,需要在类中声明一个私有构造函数,阻止外部声明。另外,再提供一个外部的访问点。代码很简单,如下:

public   class  Singleton
{
    
// 用于返回的静态实例
     private   static  Singleton m_Singleton;
    
// 私有构造函数,阻止外部使用new关键字创建这个类的新实例
     private  Singleton() { }

    
public   static  Singleton GetInstance()
    {
        
if  (m_Singleton  ==   null
        { 
            m_Singleton 
=   new  Singleton(); 
        }
        
return  m_Singleton;
    }
}

        上面的代码很简单,就不再解释什么了。需要注意的是,上面使用了“晚加载(Lazy Load)”的技术,即在使用前才实例化需要的单件。

3 对Singleton的扩展

(1)多线程下的Singleton

        普通的单件模式无法适应多线程状况下。很明显,在第一个线程判断实例是否为null后,如果阻塞了,那么很可能创建出两个或以上的Singleton实例。所以,代码需要改进:

public   class  ThreadSingleton
{
    
private   static   volatile  ThreadSingleton m_Singleton;
    
// 线程锁辅助器,没有其他用途,仅为了辅助锁定线程
     private   static   object  m_LockHelper  =   new   object ();
    
private  ThreadSingleton(){}
    
public   static  ThreadSingleton GetInstance()
    {
        
// 双检查
         if  (m_Singleton  ==   null )
        {
            
lock  (m_LockHelper)
            {
                
if  (m_Singleton  ==   null
                { 
                    m_Singleton 
=   new  ThreadSingleton(); 
                }
            }
        }
        
return  m_Singleton;
    }
}

        关键字volatile指定编译器按照代码顺序编译(有时,编译器出于优化的目的,会改变代码的执行顺序),这个关键字从严格意义上防止了线程可能的错误。m_LockHelper只是一个线程锁,不参与实际操作。其后使用了一个双检查,在第一次判断之后,锁定线程,然后再次判断。防止线程的错误。

(2)性能改善的Singleton

        如果Singleton在线程下被频繁调用,那么,可能会造成程序性能的下降。下面的方法很简单:

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

        对于只读的静态变量,.NET的机制实际上实现了下面的代码(隐含实现):

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

        该代码表示两层意思:(1).NET框架限制了静态构造器仅在一个线程内运行,即实现了多线程;(2) .NET框架下的静态构造器,使用了晚加载效果,即仅在使用时才初始化。

(3)多实例的Singleton

        Singleton模式只创建一个实例。那么,实际的隐含意思是可以创建指定个数的实例。对Singleton的真正理解是:Singleton可以创建指定个数的类的实例。既然可以生成一个,也就可以生成多个。实现多实例的Singleton,代码和前面的没有什么很大的区别。

public   class  MutiSingleton

    
private   static  MutiSingleton[] m_MutiSingleton  =   new  MutiSingleton[ 10 ];
    
private  MutiSingleton(){}
    
public   static  MutiSingleton GetInstance( int  index)
    {
        
if  (m_MutiSingleton[index]  ==   null )
        { 
            m_MutiSingleton[index] 
=   new  MutiSingleton(); 
        }
        
return  m_MutiSingleton[index];
    }
}

4 对Singleton的总结

        Singleton模式是对全局变量的改进。它避免了那些存储唯一实例的全局变量污染名称空间。Singleton也可以派生扩展,但是,因为构造器是私有的,所以不能通过这个来扩展类。此外,受限于私有的变量引用,它会和子类共享这个静态变量。所以,要想让子类工作顺利,需要借助注册表功能,让它来保存字符串和单件之间的映射。但是,单件模式在整个设计模式中不是重要的模式,应用也不多。所以,如果发现需要扩展派生Singleton,首先应该是检查代码,看看究竟需不需要这么做。

一句话归纳:Singleton模式适用于系统仅需要一个对象实例的特殊情况。类保有一个自身的静态变量,并隐藏构造函数。通过一个静态方法向外界公开自身的静态变量。考虑性能,可以使用延迟加载技术。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值