Singleton patterns 單件(創建型模式)

1、模式分類

???? 1.1? 從目的來看:

??????????????????? ?????? – 創建型(Creational)模式:負責對象創建。

??????????????????? ?????? – 結構型(Structural)模式:處理類與對象間的組合。

?????????????????????????? – 行為型(Behavioral)模式:類與對象交互中的職責分配。

???? 1.2 從范圍來看:

????????????????????????? – 類模式處理類與子類的靜態關系。

??????????????????? ????? – 對象模式處理對象間的動態關系。

2、動機(Motivation)目的??

????????????????????在軟件系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個實例,才能確保它們的邏輯正確性、以及良好的效率。

3、意圖(Intent) ????????????

??????????????????? 保證一個類僅有一個實例,并提供一個該實例的全局訪問點。

????????????????????????????????????????????????????????????????????????????????????????? ——《設計模式》GoF

4、單例模式多種實現方法

??? 4.1 單線程Singleton 模式實現

 1  class Singleton
 2     {
 3         private static Singleton instance;   
 4         private Singleton() //防止外界隨意new此對象,如果訪問級別設置成protected,那么子類可以派生,同時也也不可以實例化此對象
 5         {         
 6         }
 7         public static Singleton Instance
 8         {
 9             get {
10                 if (instance == null)  //起到延遲加載對象的作用,當用戶用不到此實例的時候
11                 {
12                     instance = new Singleton();
13                 }
14                 return instance;
15             }
16         }
17     }

單線程Singleton模式的幾個要點
????????????????? ? Singleton模式中的實例構造器可以設置為protected以允許子類派生。(同樣不可實例化對象,受保護級別限制)
????????????????? ? Singleton模式一般不要支持ICloneable接口(實例克隆),因為這可能會導致多個對象實例,與Singleton模式的初衷違背。(實現了ICloneable接口,就必須實現Clone()方法,在此方法中我們可以返回新的對象,這樣就與Singleton模式相違背了!)
????????????????? ? Singleton模式一般不要支持序列化,因為這也有可能導致多個對象實例,同樣與Singleton模式的初衷違背。(構造對象的方式:可以通過構造器,也可以通過序列化構造對象,序列化出來的對象和原來的對象地址是不一樣的,是完全的深拷貝方式(創建新的對象))
??????????????????? Singletom模式只考慮到了對象創建的管理,沒有考慮對象銷毀的管理。就支持垃圾回收的平臺和對象的開銷來講,我們一般沒有必要對其銷毀進行特殊的管理。
????????? (缺點)? 不能應對多線程環境:在多線程環境下,使用Singleton模式仍然有可能得到Singleton類的多個實例對象。(在上面的代碼第10行進行if判斷的時候,假設現在有兩個線程(A,B)同時執行到了此行,當A線程進行if判斷,此時判斷為null,就去實例化對象,但是A線程還沒來得及進行對象的實例化的時候,此時B線程就進行了if的判斷,并完成了對此對象的判斷,判斷為null,所以B線程就會去創建另一個實例,所以就創建了兩個實例!)

????4.2、多線程Singleton 模式實現

 1 class Singleton
 2     {
 3         private static volatile Singleton instance = null; //volatile(編譯器在對代碼進行編譯的時候,會對代碼進行一些微調,對代碼的順序進行調整,
volatile關鍵字就保證了編譯器不會對instance進行代碼的微調,
這樣就保證了嚴格意義上的多線程不會出現創建出多個實例的情況)
4 private static object lockHelper = new object(); //輔助器 5 private Singleton() //防止外界隨意new此對象 6 { 7 } 8 public static Singleton Instance 9 { 10 get 11 { 12 if (instance == null) 13 { 14 lock (lockHelper) 15 { 16 if (instance == null)//雙檢查 17 { 18 instance = new Singleton(); 19 } 20 } 21 } 22 return instance; 23 } 24 } 25 }

優缺點:這種實現方式對多線程來說是安全的,同時線程不是每次都加鎖,只有判斷對象實例沒有被創建時它才加鎖(如果最外層的if不加的話,那么其他線程都會進行加鎖操作,會增加額外的開銷,損失性能),加鎖后還得再進行對象是否已被創建的判斷。它解決了線程并發問題,同時避免在每個 Instance 屬性方法的調用中都出現獨占鎖定。它還允許您將實例化延遲到第一次訪問對象時發生。

volatile:

MSDN上的解釋:volatile 關鍵字表示字段可能被多個并發執行線程修改。聲明為 volatile 的字段不受編譯器優化(假定由單個線程訪問)的限制。這樣可以確保該字段在任何時間呈現的都是最新的值

???? 4.3、?使用.NET類型初始化機制實現多線程Singleton 模式(最好的方式)

1    sealed class Singleton
2     {
3         private static readonly Singleton instance = new Singleton();
4         private Singleton() //防止外界隨意new此對象
5         {
6         }
7     }

其實上面的代碼實現如果展開來的話等同于下面代碼的實現

 1   sealed class Singleton
 2     {
 3         private static readonly Singleton instance;
 4         static Singleton() //在調用instance靜態字段時會先去執行此靜態構造器,靜態構造器能保證多線程環境下只有一個線程執行了此靜態構造器,為我們自動加鎖
 5         {                  
 6             instance = new Singleton();//在靜態構造器中實例化
 7         }
 8         private Singleton() //防止外界隨意new此對象
 9         {
10         }
11     }

該類標記為 sealed 以阻止發生派生,而派生可能會增加實例。此外,變量標記為 readonly,這意味著只能在靜態初始化期間(此處顯示的示例)或在類構造函數中分配變量。

缺點:

  • 我們對實例化機制的控制權較少!在4.1和4.2中能夠在實例化之前使用非默認的構造函數或執行其他任務。由于在此實現方法中由 .NET Framework負責執行初始化,因此您沒有這些選項。
  • 無法實現延遲初始化,
  • 4.3的實現方法無法進行傳參,4.1和4.2的實現方式都可以進行傳參,主要是因為對象的實例化是在方法內部創建的(屬性實質為方法),所以我們可以把屬性寫成帶參數的方法即可!如下,對4.1方法變為帶參數的!
 1  class Singleton
 2     {
 3         private static Singleton instance;
 4         public string Name { get; set; }
 5         public int Age { get; set; }
 6         public static Singleton GetInstance(string name, int age)
 7         {
 8             if (instance == null)
 9             {
10                 instance = new Singleton(name, age);
11             }
12             return instance;
13         }
14         private Singleton(string name, int age)
15         {
16             this.Name = name;
17             this.Age = age;
18         }
19     }

5、延遲初始化

 1 public sealed class Singleton
 2  {
 3      Singleton()
 4      {
 5      }  
 6      public static Singleton Instance
 7      {
 8          get
 9         {
10             return Nested.instance;
11         }
12      }    
13     class Nested
14     {
15         static Nested()
16         {
17         }
18        internal static readonly Singleton instance = new Singleton();
19     }
20 }

?這里,初始化工作有Nested類的一個靜態成員來完成,這樣就實現了延遲初始化,并具有很多的優勢,是值得推薦的一種實現方式?

6、Singleton模式擴展
??????????? ? 將一個實例擴展到固定幾個實例,例如對象池的實現。這樣做是允許的而且是有意義的!
??????????? ? 將new 構造器的調用轉移到其他類中,例如多個類協同工作環境中,某個局部環境只需要擁有某個類的一個實例。
??????????? ? 理解和擴展Singleton模式的核心是“如何控制用戶使用new對一個類的實例構造器的任意調用”。?

?7、.NET框架中的Singleton應用

  • winform程序,你只需要點擊按鈕,彈出一個窗口,并且保證此窗口只能有一個!再點擊按鈕是無法在彈出此窗體的!
  • PC機中可能有幾個串口,但只能有一個COM1口的實例。
  • 系統中只能有一個窗口管理器。
  • .NET Remoting中服務器激活對象中的Sigleton對象,確保所有的客戶程序的請求都只有一個實例來處理。

?

?8、推薦參考書
??????????? ? 《設計模式:可復用面向對象軟件的基礎》GoF???????????????????????????? --小白看起來會有點困難
??????????? ? 《面向對象分析與設計》Grady Booch ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? --翻譯有些問題
??????????? ? 《敏捷軟件開發:原則、模式與實踐》Robert C. Martin
????????????? 《重構:改善既有代碼的設計》 Martin Fowler
??????????? ? 《Refactoring to Patterns》Joshua Kerievsky???????????????????????? --沒中文版

?9、參考

??? 《C#面向對象設計模式縱橫談》 ? ?李建忠

???? http://terrylee.cnblogs.com??? TerryLee

?

????????????????????????????????????????????????????????????????????????????????????????????????? 作者:MrZivChu

2013-08-02 15:34:03

?

?

?

?

?

?

?

?

?

?

?

?

轉載于:https://www.cnblogs.com/MrZivChu/p/Singleton_patterns.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274115.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274115.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274115.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android 第十一課 SQlite 數據庫存儲

Android 為了讓我們能夠更加方便的管理數據庫,特意提供了一個SQLiteOpenHelper幫助類,通過借助這個類就可以非常簡單的對數據庫進行創建和升級。 SQLiteOpenHelper是一個抽象類,我們要創建一個自己的幫助類去繼承它。SQLiteOpenHelper有兩個抽…

淺析SQL Server 2005中的主動式通知機制

一、引言 在開發多人同時訪問的Web應用程序(其實不只這類程序)時,開發人員往往會在緩存策略的設計上狠下功夫。這是因為,如果將這種環境下不常變更的數據臨時存放在應用程序服務器或是用戶機器上的話,可以避免頻繁地往…

Android 第十二課 使用LitePal操作數據庫(記得閱讀最后面的注意事項哦)

一、LitePal簡介 1、(新建項目LitePalTest)正式接觸第一個開源庫---LitePalLitePal是一款開源的Android 數據庫框架,它采用了對象關系映射(ORM)的模式。2、配置LitePal,編輯app/build.gradle文件,在dependencies閉包中…

listview頻繁刷新報錯

在Android編程中使用Adapter時,偶爾會出現如下錯誤:The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI t…

Android 第十三課 SharedPreferences存儲

SharedPreferences是使用鍵值對的方式來存儲數據的。當保存一條數據時,需要給這條數據提供一個對應的鍵,這樣在讀取數據的時候就可以通過這個鍵把相應的值取出來。而且支SharedPreferences還支持多種不同的數據類型存儲,例如:如果…

DSP的Gel作用

轉自:http://blog.csdn.net/azhgul/article/details/6660960最近剛在研究Davinci系,特此MARK下,以資后續學習之用。 DSP的Gel作用 1 GEL文件基本作用 當CCSStudio啟動時,GEL文件加載到PC機的內存中,如果定義了StartUp(…

解決關于登錄校園網顯示不在IP段的問題方案(要看注意事項哦!)

有時,登錄校園網,賬號和密碼都顯示正確,但是卻顯示出“賬號只能在指定IP段登錄”的問題。 那我們就提供了一個解決方案: 使用WinR,并在輸入框,輸入cmd命令:(如下)接著輸入&#xff1…

jquery插件編寫

jQuery為開發插件提拱了兩個方法,分別是: jQuery.fn.extend(object); jQuery.extend(object); jQuery.extend(object); 為擴展jQuery類本身.為類添加新的方法。可以理解為添加靜態方法。是全局的(位于jQuery命名空間內部的函數)…

gtk/Glade編程 編譯命令不成功 解決方法

摘自:http://blog.chinaunix.net/uid-26746982-id-3433656.html 當我們編寫gtk/glade程序,gcc編譯時,用如下命令: #gcc -o server server.c pkg-config --cflags --libs gtk-2.0 報錯:/tmp/ccoXadAd.o: In function …

Android 第十五課 如何使用LitePal從SQLite數據庫中刪除數據(十四課用來保留講解如何向SQLite數據庫中存入數據)

使用LitePal刪除數據的方式主要有兩種,第一種就是直接調用已存對象的delete()方法,所謂已存儲對象就是調用過save()方法的對象,或者說是通過LitePal提供的查詢API查出來的對象,都是可以直接使用delete方法來刪除對象的。這是比較簡…

頁面返回頂部(方法比較)

下面就說下簡單的返回頂部效果的代碼實現&#xff0c;附注釋說明。 1. 最簡單的靜態返回頂部&#xff0c;點擊直接跳轉頁面頂部&#xff0c;常見于固定放置在頁面底部返回頂部功能 方法一&#xff1a;用命名錨點擊返回到頂部預設的id為top的元素 html代碼 <a href"#top…

Android 第十六課 使用LitePal查詢數據

LitePal在查詢API方面做了非常多的優化&#xff0c;基本上可以滿足絕大多數場景的查詢需求&#xff0c;并且代碼也十分整潔。 例如我們需要查詢表中的所有數據&#xff1a; List<books> DataSupport.findAll(Book.class); 沒有冗長的參數列表&#xff0c;只需要調用一下…

linux創建桌面圖標,和開始菜單欄圖標

轉自&#xff1a;http://blog.csdn.net/qq_25773973/article/details/50514767 ###環境&#xff1a;Mint17&#xff0c;&#xff08;其他類似的linux系統是一樣的&#xff09; 如果開始菜單有圖標&#xff0c;創建桌面圖標很簡單&#xff0c;右鍵添加到桌面即可。 如果沒有&am…

ScrollView中使用ListView

轉自 http://blog.csdn.net/fzh0803/article/details/7971391 由于scrollview和listview不能直接共存&#xff0c;在scrollview中直接使用lsitview的話只會顯示一個條目&#xff0c;要使他們共存&#xff0c; 據我所知&#xff0c;有三種方法&#xff1a; 1。如果listview的高度…

Android 第十四課 使用LitePal添加數據(更新數據)

我們注意到當你登錄一個app&#xff0c;是不是需要先注冊呢&#xff1f;&#xff0c;所謂注冊&#xff0c;簡單地來理解是不是就是把輸入框中地數據傳入數據庫中呢&#xff1f; 這里我們設置簡單一點&#xff0c;注冊的信息只包括兩項&#xff0c;一項是用戶名&#xff0c;另一…

微信公眾平臺的服務號和訂閱號

微信公眾平臺 服務號 訂閱號 作者&#xff1a;方倍工作室 地址&#xff1a;http://www.cnblogs.com/txw1958/p/ServiceNumber-subscriptionNumber.html 什么是服務號&#xff1f; 服務號給企業和組織提供更強大的業務服務與用戶管理能力&#xff0c;幫助企業快速實現全新的公眾…

Android 第十七課 碎片的簡單用法及動態添加碎片

Fragment(碎片)是一種可以嵌入在活動當中的UI片段&#xff0c;它可以讓程序更加合理和充分的利用大屏幕的空間。碎片和活動太像了&#xff0c;同樣都包含布局&#xff0c;都有自己的聲明周期&#xff0c;可以將碎片理解為一種迷你型的活動。 新建FragmentTest項目。假設項目已經…

在Linux下禁用鍵盤、鼠標、觸摸板(筆記本)等輸入設備

在Linux系統下禁用鍵盤、觸摸板、鼠標等輸入設備&#xff0c;可以通過xinput命令來實現&#xff1a;主要涉及&#xff1a;#xinput list#xinput list-props list-number#xinput set-prop list-number func-number 1/0具體操作如下&#xff1a;step1&#xff1a;查看系統中有那些…

委托又給我惹麻煩了————記委托鏈的取消注冊、獲取返回值

今天改bug碰到了一個問題&#xff0c;有多個方法注冊到了一個事件里去&#xff0c;而這些方法本身又有點兒互斥&#xff0c;因而造成了bug&#xff0c;哥調試半天才發現&#xff0c;郁悶至極&#xff0c;遂復習了以前的知識并進行適當延伸&#xff0c;再將成果記錄及分享之&…

Python第一課

對python仰慕已久&#xff0c;今日下定決心學習。可能我是一時頭腦發熱&#xff0c;但我還是愿意堅持。 先了解一下&#xff1a;命令行模式和Python交互模式 在Windows開始菜單選擇“命令提示符”&#xff0c;就進入到命令行模式&#xff0c;它的提示符類似C:\>&#xff1a;…