设计模式学习之单件模式(Singleton)

作用:保证一个类只能有一个实例。并提供一个访问它的全局访问点。属于创建型模式。
实现要点:一.使用一个静态成员变量作为“全局”实例,这样就确保了唯一性
              二.使用静态的成员函数instance()替代new来获取该类的实例,这样就提供了全局的访问点
              三.构造函数设为private,使调用者不能用new来创建此类的实例
代码:两种方法实现单件模式,一种是Early initialization,一种是Lazy Initialization。

方法一:

//Early initialization
    class EarlySingleton
    {
        
private static EarlySingleton earlyInstance = new EarlySingleton();
        
private EarlySingleton()
        {

        }
        
public static EarlySingleton Instance()
        {
            
return earlyInstance;
        }
    }

 

方法二:

//Lazy Initialization
    class LazySingleton
    {
        
private static LazySingleton lazyInstance;
        
private LazySingleton()
        {

        }
        
public static LazySingleton Instance()
        {
            
if (lazyInstance == null)
            {
                lazyInstance 
= new LazySingleton();
            }
            
return lazyInstance;
        }
    }

 

 深入:观察代码可以看出,方法二的静态变量只有在需要使用的时候才实例化,与方法一不管什么时候都一直存在相比,更加节省系统资源。但是方法二也不是没有问题——当使用多线程时,由于可能的线程异步,某个线程已经开始实例化lazyInstance但还未完成,而另一个线程在判断lazyInstance == null时仍然为true,从而又实例化一个,这将招致严重的错误。解决方法有三个:这三个方法是:
 1、使用 [MethodImpl(MethodImplOptions.Synchronized)] ,指定instance()方法同时只能被一个线程使用

 2、lock(myObject),是对一个对象加互斥锁,只允许一个线程访问其后大括号中语句块,直到该语句块的代码执行完才解锁,解锁后才允许其他的线程执行其语句块。

3、使用 Mutex  类的 WaitOne 方法。

按这三个方法修改后的代码分别如下:

1.

using System.Threading;
using System.Runtime.CompilerServices; 
//Lazy Initialization
    class LazySingleton
    {
        
private static LazySingleton lazyInstance;
        
private LazySingleton()
        {

        }
        [MethodImpl(MethodImplOptions.Synchronized)] 
//方法的同步属性 
        public static LazySingleton Instance()
        {
            
if (lazyInstance == null)
            {
                lazyInstance 
= new LazySingleton();
            }
            
return lazyInstance;
        }
    }

2.

using System.Threading;
//Lazy Initialization
    class LazySingleton
    {
        
private static LazySingleton lazyInstance;
        
static object myObject = new object(); 
        
private LazySingleton()
        {

        }
        
public static LazySingleton Instance()
        {
            
lock (myObject)
            {
                
if (lazyInstance == null)
                {
                    lazyInstance 
= new LazySingleton();
                }
                
return lazyInstance;
            }
        }

    }

3.

using System.Threading;
//Lazy Initialization
    class LazySingleton
    {
        
private static LazySingleton lazyInstance;
        
static object myObject = new object();
        
private static Mutex mut = new Mutex();
        
private LazySingleton()
        {

        }
        
public static LazySingleton Instance()
        {
            mut.WaitOne(); 
           
            
if (lazyInstance == null)
            {
                lazyInstance 
= new LazySingleton();
            }

            mut.ReleaseMutex(); 
            
return lazyInstance;
        }
    }

 

发现很多设计模式的作者都是写到此为止。其实还未结束,James.W.Cooper在他的书里指出:当唯一的实例已经存在时,最好给调用者抛出一个明确的异常信息。这个很有道理,如果单件实例已存在,而调用者不知道,我们不吭声就把这个已存在的单件实例返回给他,很有可能导致他犯更大的错误。

修改Instance()中代码:

if (lazyInstance == null)
{
   lazyInstance 
= new LazySingleton();
}
else
{
   
throw new Exception("Singleton should be init just once");
}

 

 

posted @ 2008-11-03 15:54  MichaelChen  阅读(455)  评论(1编辑  收藏  举报