<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      單例模式(Singleton)的6種實現

      1.1.1 摘要

             在我們日常的工作中經常需要在應用程序中保持一個唯一的實例,如:IO處理,數據庫操作等,由于這些對象都要占用重要的系統資源,所以我們必須限制這些實例的創建或始終使用一個公用的實例,這就是我們今天要介紹的——單例模式(Singleton)。

             使用頻率clip_image001

             單件模式(Singleton):保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

       

      1.1.2 正文

       

      singleton

      圖1單例模式(Singleton)結構圖

       

             單例模式(Singleton)是幾個創建模式中最對立的一個,它的主要特點不是根據用戶程序調用生成一個新的實例,而是控制某個類型的實例唯一性,通過上圖我們知道它包含的角色只有一個,就是Singleton,它擁有一個私有構造函數,這確保用戶無法通過new直接實例它。除此之外,該模式中包含一個靜態私有成員變量instance與靜態公有方法Instance()。Instance()方法負責檢驗并實例化自己,然后存儲在靜態成員變量中,以確保只有一個實例被創建。

       

      clip_image002

      圖2單例模式(Singleton)邏輯模型

       

             接下來我們將介紹6中不同的單例模式(Singleton)的實現方式。這些實現方式都有以下的共同點:

       

        1. 有一個私有的無參構造函數,這可以防止其他類實例化它,而且單例類也不應該被繼承,如果單例類允許繼承那么每個子類都可以創建實例,這就違背了Singleton模式“唯一實例”的初衷。
        2. 單例類被定義為sealed,就像前面提到的該類不應該被繼承,所以為了保險起見可以把該類定義成不允許派生,但沒有要求一定要這樣定義。
        3. 一個靜態的變量用來保存單實例的引用。
        4. 一個公有的靜態方法用來獲取單實例的引用,如果實例為null即創建一個。

       

      版本一線程不安全

       

      /// <summary>
      /// A simple singleton class implements.
      /// </summary>
      public sealed class Singleton
      {
          private static Singleton _instance = null;
      
          /// <summary>
          /// Prevents a default instance of the 
          /// <see cref="Singleton"/> class from being created.
          /// </summary>
          private Singleton()
          {
          }
      
          /// <summary>
          /// Gets the instance.
          /// </summary>
          public static Singleton Instance
          {
              get { return _instance ?? (_instance = new Singleton()); }
          }
      }

            以上的實現方式適用于單線程環境,因為在多線程的環境下有可能得到Singleton類的多個實例。假如同時有兩個線程去判斷

      (null == _singleton),并且得到的結果為真,那么兩個線程都會創建類Singleton的實例,這樣就違背了Singleton模式“唯一實例”的初衷。

       

      版本二線程安全

       

      /// <summary>
      /// A thread-safe singleton class.
      /// </summary>
      public sealed class Singleton
      {
          private static Singleton _instance = null;
          private static readonly object SynObject = new object();
      
          Singleton()
          {
          }
      
          /// <summary>
          /// Gets the instance.
          /// </summary>
          public static Singleton Instance
          {
              get
              {
                  // Syn operation.
                  lock (SynObject)
                  {
                      return _instance ?? (_instance = new Singleton());
                  }
              }
          }
      }

       

              以上方式的實現方式是線程安全的,首先我們創建了一個靜態只讀的進程輔助對象,由于lock是確保當一個線程位于代碼的臨界區時,另一個線程不能進入臨界區(同步操作)。如果其他線程試圖進入鎖定的代碼,則它將一直等待,直到該對象被釋放。從而確保在多線程下不會創建多個對象實例了。只是這種實現方式要進行同步操作,這將是影響系統性能的瓶頸和增加了額外的開銷。

       

      Double-Checked Locking

             前面講到的線程安全的實現方式的問題是要進行同步操作,那么我們是否可以降低通過操作的次數呢?其實我們只需在同步操作之前,添加判斷該實例是否為null就可以降低通過操作的次數了,這樣是經典的Double-Checked Locking方法。

       

      /// <summary>
      /// Double-Checked Locking implements a thread-safe singleton class
      /// </summary>
      public sealed class Singleton
      {
          private static Singleton _instance = null;
          // Creates an syn object.
          private static readonly object SynObject = new object();
      
          Singleton()
          {
          }
      
          public static Singleton Instance
          {
              get
              {
                  // Double-Checked Locking
                  if (null == _instance)
                  {
                      lock (SynObject)
                      {
                          if (null == _instance)
                          {
                              _instance = new Singleton();
                          }
                      }
                  }
                  return _instance;
              }
          }
      }

            

             在介紹第四種實現方式之前,首先讓我們認識什么是,當字段被標記為beforefieldinit類型時,該字段初始化可以發生在任何時候任何字段被引用之前。這句話聽起了有點別扭,接下來讓我們通過具體的例子介紹。

       

      /// <summary>
      /// Defines a test class.
      /// </summary>
      class Test
      {
          public static string x = EchoAndReturn("In type initializer");
      
          public static string EchoAndReturn(string s)
          {
              Console.WriteLine(s);
              return s;
          }
      }

            上面我們定義了一個包含靜態字段和方法的類Test,但要注意我們并沒有定義靜態的構造函數。

       

      singleton2

      圖3 Test類的IL代碼

       

      class Test
      {
          public static string x = EchoAndReturn("In type initializer");
      
          // Defines a parameterless constructor.
          static Test()
          {
          }
      
          public static string EchoAndReturn(string s)
          {
              Console.WriteLine(s);
              return s;
          }
      }

         

          上面我們給Test類添加一個靜態的構造函數。

       

         singleton3

      圖4 Test類的IL代碼

       

             通過上面Test類的IL代碼的區別我們發現,當Test類包含靜態字段,而且沒有定義靜態的構造函數時,該類會被標記為beforefieldinit。

             現在也許有人會問:“被標記為beforefieldinit和沒有標記的有什么區別呢”?OK現在讓我們通過下面的具體例子看一下它們的區別吧!

       

      class Test
      {
          public static string x = EchoAndReturn("In type initializer");
      
          static Test()
          {
          }
      
          public static string EchoAndReturn(string s)
          {
              Console.WriteLine(s);
              return s;
          }
      }
      
      class Driver
      {
          public static void Main()
          {
              Console.WriteLine("Starting Main");
              // Invoke a static method on Test
              Test.EchoAndReturn("Echo!");
              Console.WriteLine("After echo");
              Console.ReadLine();
      
              // The output result:
              // Starting Main
              // In type initializer
              // Echo!
              // After echo            
          }
      }

           我相信大家都可以得到答案,如果在調用EchoAndReturn()方法之前,需要完成靜態成員的初始化,所以最終的輸出結果如下:

       

      singleton4

      圖5輸出結果

          接著我們在Main()方法中添加string y = Test.x,如下:

       

      public static void Main()
      {
          Console.WriteLine("Starting Main");
          // Invoke a static method on Test
          Test.EchoAndReturn("Echo!");
          Console.WriteLine("After echo");
      
          //Reference a static field in Test
          string y = Test.x;
          //Use the value just to avoid compiler cleverness
          if (y != null)
          {
              Console.WriteLine("After field access");
          }
          Console.ReadKey();
      
          // The output result:
          // In type initializer
          // Starting Main
          // Echo!
          // After echo
          // After field access
      
      }

       

      singleton5

      圖6 輸出結果

              通過上面的輸出結果,大家可以發現靜態字段的初始化跑到了靜態方法調用之前,Wo難以想象啊!

              最后我們在Test類中添加一個靜態構造函數如下:

       

      class Test
      {
          public static string x = EchoAndReturn("In type initializer");
      
          static Test()
          {
          }
      
          public static string EchoAndReturn(string s)
          {
              Console.WriteLine(s);
              return s;
          }
      }

       

      singleton6

      圖7 輸出結果

       

             理論上,type initializer應該發生在”Echo!”之后和”After echo”之前,但這里卻出現了不唯一的結果,只有當Test類包含靜態構造函數時,才能確保type initializer的初始化發生在”Echo!”之后和”After echo”之前。

      所以說要確保type initializer發生在被字段引用時,我們應該給該類添加靜態構造函數。接下來讓我們介紹單例模式的靜態方式。

       

      靜態初始化

       

      public sealed class Singleton
      {
          private static readonly Singleton _instance = new Singleton();
      
          // Explicit static constructor to tell C# compiler
          // not to mark type as beforefieldinit
          static Singleton()
          {
          }
      
          /// <summary>
          /// Prevents a default instance of the 
          /// <see cref="Singleton"/> class from being created.
          /// </summary>
          private Singleton()
          {
          }
      
          /// <summary>
          /// Gets the instance.
          /// </summary>
          public static Singleton Instance
          {
              get
              {
                  return _instance;
              }
          }
      }

              以上方式實現比之前介紹的方式都要簡單,但它確實是多線程環境下,C#實現的Singleton的一種方式。由于這種靜態初始化的方式是在自己的字段被引用時才會實例化。

             讓我們通過IL代碼來分析靜態初始化。

       

      singleton7

      圖8靜態初始化IL代碼

       

              首先這里沒有beforefieldinit的修飾符,由于我們添加了靜態構造函數當靜態字段被引用時才進行初始化,因此即便很多線程試圖引用_instance,也需要等靜態構造函數執行完并把靜態成員_instance實例化之后可以使用。

       

      延遲初始化

       

      /// <summary>
      /// Delaies initialization.
      /// </summary>
      public sealed class Singleton
      {
          private Singleton()
          {
          }
      
          /// <summary>
          /// Gets the instance.
          /// </summary>
          public static Singleton Instance { get { return Nested._instance; } }
      
          private class Nested
          {
              // Explicit static constructor to tell C# compiler
              // not to mark type as beforefieldinit
              static Nested()
              {
              }
      
              internal static readonly Singleton _instance = new Singleton();
          }
      }

       

         這里我們把初始化工作放到Nested類中的一個靜態成員來完成,這樣就實現了延遲初始化。

       

      Lazy<T> type

       

      /// <summary>
      /// .NET 4's Lazy<T> type
      /// </summary>
      public sealed class Singleton
      {
          private static readonly Lazy<Singleton> lazy =
              new Lazy<Singleton>(() => new Singleton());
      
          public static Singleton Instance { get { return lazy.Value; } }
      
          private Singleton()
          {
          }
      }

       

           這種方式的簡單和性能良好,而且還提供檢查是否已經創建實例的屬性IsValueCreated。

       

      具體例子

           現在讓我們使用單例模式(Singleton)實現負載平衡器,首先我們定義一個服務器類,它包含服務器名和IP地址如下:

       

      /// <summary>
      /// Represents a server machine
      /// </summary>
      class Server
      {
          // Gets or sets server name
          public string Name { get; set; }
      
          // Gets or sets server IP address
          public string IP { get; set; }
      }

           由于負載平衡器只提供一個對象實例供服務器使用,所以我們使用單例模式(Singleton)實現該負載平衡器。

       

      /// <summary>
      /// The 'Singleton' class
      /// </summary>
      sealed class LoadBalancer
      {
          private static readonly LoadBalancer _instance =
              new LoadBalancer();
      
          // Type-safe generic list of servers
          private List<Server> _servers;
          private Random _random = new Random();
      
          static LoadBalancer()
          {
          }
      
          // Note: constructor is 'private'
          private LoadBalancer()
          {
              // Load list of available servers
              _servers = new List<Server> 
                  { 
                    new Server{ Name = "ServerI", IP = "192.168.0.108" },
                    new Server{ Name = "ServerII", IP = "192.168.0.109" },
                    new Server{ Name = "ServerIII", IP = "192.168.0.110" },
                    new Server{ Name = "ServerIV", IP = "192.168.0.111" },
                    new Server{ Name = "ServerV", IP = "192.168.0.112" },
                  };
          }
      
          /// <summary>
          /// Gets the instance through static initialization.
          /// </summary>
          public static LoadBalancer Instance
          {
              get { return _instance; }
          }
      
      
          // Simple, but effective load balancer
          public Server NextServer
          {
              get
              {
                  int r = _random.Next(_servers.Count);
                  return _servers[r];
              }
          }
      }

        上面負載平衡器類LoadBalancer我們使用靜態初始化方式實現單例模式(Singleton)。

       

      static void Main()
      {
          LoadBalancer b1 = LoadBalancer.Instance;
          b1.GetHashCode();
          LoadBalancer b2 = LoadBalancer.Instance;
          LoadBalancer b3 = LoadBalancer.Instance;
          LoadBalancer b4 = LoadBalancer.Instance;
      
          // Confirm these are the same instance
          if (b1 == b2 && b2 == b3 && b3 == b4)
          {
              Console.WriteLine("Same instance\n");
          }
      
          // Next, load balance 15 requests for a server
          LoadBalancer balancer = LoadBalancer.Instance;
          for (int i = 0; i < 15; i++)
          {
              string serverName = balancer.NextServer.Name;
              Console.WriteLine("Dispatch request to: " + serverName);
          }
      
          Console.ReadKey();
      }

       

      clip_image002[9]

      圖9 LoadBalancer輸出結果

       

      1.1.3 總結

       

      單例模式的優點:

      單例模式(Singleton)會控制其實例對象的數量,從而確保訪問對象的唯一性。

      1. 實例控制:單例模式防止其它對象對自己的實例化,確保所有的對象都訪問一個實例。
      2. 伸縮性:因為由類自己來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。

       

      單例模式的缺點:

      1. 系統開銷。雖然這個系統開銷看起來很小,但是每次引用這個類實例的時候都要進行實例是否存在的檢查。這個問題可以通過靜態實例來解決。
      2. 開發混淆。當使用一個單例模式的對象的時候(特別是定義在類庫中的),開發人員必須要記住不能使用new關鍵字來實例化對象。因為開發者看不到在類庫中的源代碼,所以當他們發現不能實例化一個類的時候會很驚訝。
      3. 對象生命周期。單例模式沒有提出對象的銷毀。在提供內存管理的開發語言(比如,基于.NetFramework的語言)中,只有單例模式對象自己才能將對象實例銷毀,因為只有它擁有對實例的引用。在各種開發語言中,比如C++,其它類可以銷毀對象實例,但是這么做將導致單例類內部的指針指向不明。

       

      單例適用性

      使用Singleton模式有一個必要條件:在一個系統要求一個類只有一個實例時才應當使用單例模式。反之,如果一個類可以有幾個實例共存,就不要使用單例模式。

      不要使用單例模式存取全局變量。這違背了單例模式的用意,最好放到對應類的靜態成員中。

      不要將數據庫連接做成單例,因為一個系統可能會與數據庫有多個連接,并且在有連接池的情況下,應當盡可能及時釋放連接。Singleton模式由于使用靜態成員存儲類實例,所以可能會造成資源無法及時釋放,帶來問題。

       

      參考:

      http://csharpindepth.com/Articles/General/Singleton.aspx

      posted @ 2011-10-30 21:27  JK_Rush  閱讀(113882)  評論(43)    收藏  舉報
      主站蜘蛛池模板: 久热久精久品这里在线观看| aaa少妇高潮大片免费看| 成全我在线观看免费第二季| 国产精品人妻系列21p| 激情四射激情五月综合网| 黄骅市| 日韩中文字幕一二三视频| 夜夜添无码一区二区三区| 亚洲人亚洲人成电影网站色 | 久久综合久中文字幕青草| 日韩视频中文字幕精品偷拍| 最近中文字幕完整版| 亚洲电影天堂av2017| 开心激情站开心激情网六月婷婷| 老色鬼永久精品网站| 日本三级香港三级三级人妇久| 色综合久久久久综合体桃花网| 亚洲免费一区二区av| 狠狠色丁香婷婷综合尤物| 国产一区二区三区小说| 亚洲无av在线中文字幕| 亚洲AV国产福利精品在现观看| 韩国免费A级毛片久久| 在线播放国产精品三级网| 男女性高爱潮免费网站| 亚洲国产良家在线观看| 日韩国产精品中文字幕| 色噜噜在线视频免费观看| 97人妻天天爽夜夜爽二区 | 国产裸体永久免费无遮挡| 91区国产福利在线观看午夜 | 亚洲午夜香蕉久久精品| 亚洲精品国产第一区二区| 清徐县| 国产精品午夜福利91| 国产综合久久久久鬼色| 麻豆精产国品一二三产| 亚洲精品无amm毛片| 好大好硬好爽免费视频| 亚洲精品综合网二三区| 国产美女69视频免费观看|