單例模式

解讀設計模式----單例模式(Singleton Pattern)

      單例模式可以保證一個類有且只有一個實例,並提供一個訪問它的全局訪問點.在程序設計中,有很多情況需要確保一個類只能有一個實例.從這句話可以看出,Singleton模式的核心:如何控制用戶使用new對一個類的實例構造器的任意調用。如何繞過常規的構造器,提供一種機制來保證一個類只有一個實例?這應該是類設計者的責任,而不是使用者的責任。

 一、單例模式意圖
      保證一個類有且只有一個實例,並提供一個訪問它的全局訪問點。

二、單例模式UML圖(該圖來至http://www.dofactory.com/)
      

三、示例解說單例模式
      看看下面這個簡單的示例:

 1namespace DesignPattern.Singleton
 2{
 3    public class Singleton
 4    {
 5        //靜態私有屬性
 6        private static Singleton instance;
 7
 8        /// <summary>
 9        /// 私有構造器--讓類的使用者調用不到此構造器
10        /// </summary>
11        private Singleton()
12        { }
13
14        public static Singleton Instance
15        {
16            get 
17            {
18                if (instance == null)
19                {
20                    instance = new Singleton();
21                }
22                return instance;  //返回的總是第一次實例的對象
23            }
24        }
25    }
26
27    //測試類
28    class TestSingleton
29    {
30        public static void Main2(string[] args)
31        {
32            Singleton t1 = Singleton.Instance;
33            Singleton t2 = Singleton.Instance;
34            Console.WriteLine(object.ReferenceEquals(t1, t2) == true);
35        }
36    }
37}

     提供一個靜態的私有屬性,並提供get來實現一個簡單的單例.此外我們還可以通過靜態只讀屬性來實現.看看下面這個MSDN上提供的示例:

 1/// <summary>
 2/// MSDN上Singleton模式的實現
 3/// </summary>

 4public class MsdnSingleton
 5{
 6   //聲明的同時進行初始化
 7   public static readonly MsdnSingleton Instance = new MsdnSingleton();
 8        
 9   /// <summary>
10   /// 私有構造器
11   /// </summary>

12   private MsdnSingleton()
13   {
14   }

15}

      這樣的單例實現的實質等同於提供一個靜態的屬性字段,通過靜態構造器來初始化這個屬性.因爲要想訪問靜態字段,那靜態構造器就首先執行,下面是代碼示例:

 1public class SameSingleton
 2{
 3   //要想訪問靜態字段,那靜態構造器就首先執行
 4   public static readonly SameSingleton Instance;
 5        
 6   /// <summary>
 7   /// 靜態構造器-初始化Instance
 8   /// 靜態構造器-完成靜態字段(Instance)的初始化
 9   /// </summary>

10  static SameSingleton()
11  {
12      Instance = new SameSingleton();
13  }

14
15  /// <summary>
16  /// 私有構造器
17  /// </summary
18  private SameSingleton()

19  {
20 
21  }

22}

      上面的實現完全可以達到單例模式的意圖,保證一個類僅且有一個實例,並提供一個全局訪問點.而這在實際應用我們還得注意一點,就是在多線程的調用.於此,我們還得保證線程安全.要保證線程安全其實也是很簡單就可以實現的,只需要通過加鎖和雙重判斷就OK,下面是簡單的多線程的線程安全的實現:

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5//多線程的Singleton模式實現
 6namespace DesignPattern.Singleton
 7{
 8    public class SingletonMultithread
 9    {
10        private static object lockHelper = new object();
11
12        private static volatile SingletonMultithread instane = null;
13        public static SingletonMultithread Instane
14        {
15            get 
16            {
17                if (instane == null)  //雙檢查
18                {
19                    lock (lockHelper)
20                    {
21                        if (instane == null)
22                        {
23                            instane = new SingletonMultithread();
24                        }

25                    }

26                }

27                return instane;
28            }

29        }

30        
31
32        //私有構造方法
33        private SingletonMultithread() 
34        {
35
36        }

37    }

38
39    class TestSingletonMultithread
40    {
41        public static void Main()
42        {
43            SingletonMultithread s1 = SingletonMultithread.Instane;
44            SingletonMultithread s2 = SingletonMultithread.Instane;
45            Console.WriteLine(object.ReferenceEquals(s1, s2) == true);
46        }

47    }

48}

49

其中:private static volatile Singleton instance=null;
--volatile:保證特定平臺的實現必須不要去從新調整指令,保證對象構造的一個非常嚴格的順序。

四、真實項目中的單例
      我曾經做過一個網球場的管理系統,客戶要求使用C/S,(隨便PS下客戶,在我做需求的時候建議客戶做B/S系統,管理和部署就很方便,也不用帶上幾百M的.NET Frameworks去裝在客戶電腦上了。可好心討不了客戶的笑顏,他硬說我是在給他做網頁,還說他要的是軟件不是網頁,汗過........),在使用C/S做程序的時候我想大家都遇到過這樣的情況,無論是通過按扭點擊還是菜單來導航,通常我們是像下面這樣實現的:

1private void ratingToolStripMenuItem_Click(object sender, EventArgs e)
2{
3    ratForm rat = new ratForm();
4    rat.MdiParent = this;
5    rat.Show();
6
7}

     我這裏是使用的菜單控件,通過點擊打開新窗體。如果是這樣問題就出現了,每當我們點擊一次菜單上的菜單項就會啓動一個窗體,點幾次就會啓動幾個窗體。見下圖:


      這樣顯然是不符合要求的,我們應該做到讓每個窗體只能Show一個出來,這時 單例模式 就能派上用場了。要保證外部不能創建類的實例,才單例中就是通過設置構造方法爲私有private,所謂模式可說是一種設計套路,這裏我們就依葫蘆畫瓢來畫一次單例,設置構造方法私有,代碼如下;

1private ratForm()
2{
3    InitializeComponent();
4}

      通過一個靜態方法來對完成靜態屬性的初始化;

 1private static ratForm ratf = null;
 2public static ratForm GetInstance()
 3{
 4   if (ratf == null || ratf.IsDisposed)
 5   {
 6      ratf = new ratForm();
 7      ratf.MdiParent = mainForm.ActiveForm;
 8   }

 9   return ratf;
10}

     通過單例模式的引入,私有了構造方法,並通過一個靜態的方法初始化靜態字段,保證了類的唯一實例,方法GetInstance()就是單例的全局訪問點。這樣設計後就通過GetInstance()方法就得了這個窗體的唯一實例。

1private void ratingToolStripMenuItem_Click(object sender, EventArgs e)
2{
3    //ratForm rat = new ratForm();
4    //rat.MdiParent = this;
5    //rat.Show();
6    ratForm.GetInstance().Show();
7}

     通過單例模式的引入,改善了程序的設計,在窗體調用處只需要通過全局訪問點這個靜態方法就可以得到唯一的實例對象,然後調用其Show()方法,就達到了我們的要求。

五、使用單線程Singleton模式要點
--Singleton模式中的實例構造器可以設置爲protected以也許子類派生。
--Singleton模式一般不要支持ICloneable接口,因爲這可能導致對個對象實例,與Singleton的意圖違背。
--Singleton模式一般不要支持序列化,因爲這也有可能導致多個對象實例,同樣與Singleton模式的意圖違背。
--Singleton模式只考慮到了對象創建的管理,沒有考慮對銷燬的管理。對於自帶垃圾回收的平臺可不考慮這點。

上面總結源於MSDN WebCast


轉載請註明出處:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章