單例模式在Java和C#中的實現

   單例模式算是最常見和最容易理解一種設計模式了。通常是指某一個類只有一實例存在,存在的空間我認爲可以理解爲該類所在的應用系統內,還有一種是在某一個容器內單一存在,比如像spring的IOC容器(作用域爲singleton的bean在容器內是單例存在的),也可以是個簡單的HashMap。

單例模式的實現通常分兩種,按習慣叫法是餓漢式和懶漢式,這兩種的區別主要在於是否延遲初始化。以下是java的餓漢式單例實現:

public class SingletonDemo {
     //私有默認構造函數
      private SingletonDemo() {}
     //已經自行實例化 
     private static final SingletonDemo single = new SingletonDemo();

     public static SingletonDemo getInstance() {
         return single;
     }
}


C#的實現與這個基本無異,單例的兩個實現步驟是一私有化默認構造函數,使得類不可以在外部通過new操作實例化(注:可以利用反射實例化),

二是內部自身實例化了一個對象供外部使用。那麼取得一個SingletonDemo對象只能通過它的靜態方法getInstance()了。我們再來看懶漢式的實現:

public class SingletonDemo {

      private SingletonDemo() {}
      //注意這裏沒有final    
      private static SingletonDemo single=null;

      public synchronized static SingletonDemo getInstance() {
           if (single == null) {  
             single = new SingletonDemo();
         }  
        return single;
     }
 }


C#實現

public class SingletonDemo
{
       private static SingletonDemo instance;
       private static object _lock=new object();

       private SingletonDemo()
       { }

       public static SingletonDemo GetInstance()
       {
               if(instance==null)
               {
                      lock(_lock)
                      {
                             if(instance==null)
                             {
                                     instance=new SingletonDemo();
                             }
                      }
               }
               return instance;
       }
}


懶漢式主要在於使用時再實例化,可以說二者區別不大。另外懶漢式的一個缺點是要處理多線程調用而產生多個實例的問題,java使用了synchronized同步方法,而C#使用的是lock互斥鎖。從這點上來說本人更喜歡餓漢式的簡潔。

   由上面我們已經知道了兩種實現方式區別在於類成員的初始化順序,我們看看java的成員初始化順序:靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器

很顯然我們還可以在靜態初始塊中爲single賦值
static final SingletonDemo single;

static{
 single=new SingletonDemo();
//還可以乾點其他事,比如啓動一個hibernate的SessionFactory,哈哈
}
再看C#的,C#中是沒有靜態塊這一說的,代替它的是靜態函數
static readonly SingletonDemo single;
static SingletonDemo()
{
single=new SingletonDemo();
}

這裏要提下的是有些人喜歡在靜態塊中做一些賦值或操作,NHibernate(.net版的hibernate)的示例有這麼一段:

public class NHibernateHelper 
{
	public static readonly Configuration _Configuration;
        private const string _CurrentSessionKey = "nhibernate.current_session";
        private static readonly ISessionFactory _SessionFactory;

        static NHibernateHelper()
        {
            log4net.Config.XmlConfigurator.Configure();
            _Configuration = new Configuration();
             _SessionFactory = _Configuration.Configure().BuildSessionFactory();
          
        }
}

當hibernate配置文件中的數據庫配置存在錯誤時,這裏將出現異常,而由於靜態函數只在類初始化時運行一次,所以這個異常是不能彌補的,我們只能重啓應用再試一次了。

我們再實現一個在容器內的單例,這回來個C#版的吧:

 public class DALFactory
    {
        private static Hashtable cacheDAL = new Hashtable();

        public static T createDAL<T>()
        {
            string CacheKey = typeof(T).FullName;//使用類全名作爲key
            T dal = (T)cacheDAL[CacheKey];
            if (dal == null)
            {
                lock (cacheDAL)
                {
                    if (dal == null)
                    {
                        Type t = typeof(T);
                        dal = (T)Activator.CreateInstance(t);//反射實例化類
                        try
                        {
                            cacheDAL.Add(CacheKey, dal);
                        }
                        catch (ArgumentException) { }
                    }
                }
            }
            return dal;
        }
    }																
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章