單例模式(Singleton Pattern)

来源:https://www.cnblogs.com/ygsworld/archive/2019/04/10/10683483.html
-Advertisement-
Play Games

單例模式概述 定義:確保一個類只有一個實例,並提供一個全局訪問點來訪問這個實例 簡單的說,就是你有且只有一個女朋友(有多個女朋友的模式不是這裡~~),並且你的女朋友很特殊,從來只聽你的話,所以別人想和她交流(訪問她)就必須通過你(全局訪問點)來和她交流。 系統中用到單例模式的地方很多,比如Windo ...


  • 單例模式概述

定義確保一個類只有一個實例,並提供一個全局訪問點來訪問這個實例

簡單的說,就是你有且只有一個女朋友(有多個女朋友的模式不是這裡~~),並且你的女朋友很特殊,從來只聽你的話,所以別人想和她交流(訪問她)就必須通過你(全局訪問點)來和她交流。

系統中用到單例模式的地方很多,比如Windows系統點擊開始只能出現一個開始界面,Ctrl+Alt+. 只能出現一個資源管理器,每個進程有且對應唯一一個進程ID等等。單例模式是為了讓資源得到最大化利用,不浪費資源。同時假如不採用此模式,就可能在不同時刻打開同一個界面,但界面中的內容又各不相同,因而用戶極易產生誤解,影響使用效率。因此單例模式在系統中的應用非常重要。

要點a.某一個單例類只能有一個實例

      b.必須自行創建這個實例

      c.必須向系統提供這個實例;

  • 單例模式的結構與實現

結構: 

  1. 我們考慮一個問題,每一個類都會有它的預設構造函數,或者我們重寫一個構造函數,這個函數都是在創建這個類的實例的時候自動調用的。即對對象進行初始化操作。所以我們每次new的時候都會有一個新的對象,當然這是不符合單例模式的要求的。因此為了滿足單例模式的要求,就必須對類中的函數進行修改,怎麼修改呢,一步一步來(個人覺得這個理解還是挺重要的)。
      1. 首先,我們類的實例化不能在外部進行(單例類自行提供這個實例),即不能每次new都調用構造函數,因此將構造函數設為private類型
      2. 既然構造函數是private的,那怎麼樣調用呢??通過公有方法可以調用private函數,返回實例
      3. 看到這裡,或許有人就有疑問了,公有方法(public ... ....)是在類的對象生成後才可以調用的,但是對象的創建又必須通過構造函數,而這裡構造函數又必須通過公有方法調用,不就形成了一個雞生蛋,蛋孵雞的問題了嗎??好了,誰先誰後,我們先辯論下吧.....其實,靜態方法的使用,能很好的解決這個問題,將公有方法(函數)設為靜態方法,我們就能通過類名.方法名去調用它,繼而調用私有構造函數,產生對象。
      4. 再有,單例模式創建的女朋友只能是一個,那又怎麼確定呢?怎麼確定你的女朋友是唯一的而且你沒有偷換呢?(~~皮一下),我們就要為這個單例類添加一個變數了,用來確認是否唯一,由於創建的整個入口是靜態公有方法,所以在那時就要判斷是否唯一了,如果該單例類有了一個女朋友,判斷後便不再創建,如果當前沒有,則分配一個。而靜態成員函數可以直接訪問類的靜態數據和函數成員,而訪問非靜態成員,必須通過對象名,這有陷入雞和蛋的問題里了,所以,該變數設為靜態變數就很方便了,它也滿足為整個類服務的特性。
      5. 總結下步驟 :(1)私有構造函數;(2)公有方法調用私有函數;(3)設為靜態方法;(4)添加靜態變數;(5)根據變數數判斷是否生成女朋友(唯一的對象);
  2. 上圖中:↓↓↓↓↓
  3. Singleton(單例),在單例類的內部創建它的唯一實例
  4. Getinstance(靜態方法),通過它產生唯一實例
  5. instance(靜態變數),判斷是否可以產生實例

 實現:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace Singleton
 7 {
 8     class Singleton
 9 {
10     private static Singleton instance = null;//靜態私有成員變數
11     
12     //私有構造函數
13     private Singleton()
14     {
15         Console.WriteLine("恭喜你,獲得一個女朋友~~");
16     }
17     
18     //靜態公有方法,返回實例
19     public static Singleton Getinstance()
20     {
21         if(instance == null)//沒女朋友
22             instance = new Singleton();//生成一個吧
23         return instance;//有就返回當前的,
24     }
25 }
26     class Program
27     {
28         static void Main(string[] args)
29         {
30             Singleton s1 = Singleton.Getinstance();
31             Singleton s2 = Singleton.Getinstance();
32             if (s1 == s2)
33             {
34                 Console.WriteLine("怎麼能想要共有一個女朋友呢?S2 趕緊換一個吧...");
35             }
36         }
37     }
38 }

 結果:

  •  餓漢式單例和懶漢式單例

 剛看到這兩個單例的名字時還是有點好笑的,如此這麼生動形象呢,就好像餓漢式單身(連溫飽都滿足不了,何來女朋友呢),懶漢式(好吃懶做的,也很難...)不亂扯了,回主題。餓漢式單例正如餓漢一樣,很餓很餓的人最想要的就是立即馬上吃東西。因此餓漢式單例在定義靜態變數時就實例化了單例類,因為實在太餓了啊,等不及了

 1 class EagetSingleton
 2 {
 3     private static EagetSingleton instance = new EagetSingleton();//靜態變數實例化單例類
 4     
 5     private EagetSingleton(){}
 6     
 7     public static EagetSingleton GetInstance()
 8     {
 9         return instance;
10     }
11 }

 

懶漢式單例類則是在類第一次被引用時將自己實例化,單例類被載入時不會實例化,所以這很符合懶漢的氣質~但是在這裡要註意的是,在定義靜態變數時沒有實例化單例類,而是在第一次調用靜態方法時實例化單例類,這就會產生問題,高併發,多線程實現懶漢式單例時會創建多個對象,從而違背了單例模式的設計意圖。也就是還是要對女朋友的個數進行判斷。這要怎麼辦呢?在多線程的情況下,就要對該代碼段進行控制,即每次只讓一個線程進入並創建實例,也就是相當於現在的“共用女友”,幫你拍照啊,陪你去看電影啊 ,巴拉巴拉。但是,該“共用女友”有且只有一個,即單例類的唯一實例。所以,土豪們(各個線程)得一個一個租用,上一個用完了下一個才能租用。因此代碼如下:

 1 class LazytSingleton
 2 {
 3     private static LazytSingleton instance = null;
 4     private static readonly object synRoot = new object();//看做一個門。
 5     //程式運行時創建只讀輔助對象
 6         
 7     private LazytSingleton(){}
 8     
 9     public static LazytSingleton GetInstance()
10     {
11         if(instance == null)//在房間外問:房間里有人嗎 ? 沒人回應 ,可能沒,可能下一秒有人進去 ,我卻以為沒人
12         {
13             lock(synRoot)//第二次判斷 //把門關了,外麵線程進不來,只能裡面的出來,外面的才能進
14             {
15                 if(instance == null)//繼續問,房間里有人嗎?  有就真的有,沒有就真的沒
16                 {
17                     instance = new LazytSingleton();//創建實例
18                 }
19             }
20         }
21     }
22 }

二者比較:

  • 餓漢式單例

優點:無需考慮多線程同時訪問的問題,確保實例唯一性。調用速度和反應時間快於懶漢模式,因為餓漢一開始就創建,後面則直接拿來用就可以了。

缺點:不管單例對象是否需要,都會在類載入時創建,這樣不如懶漢式單例,資源利用不高,且載入時間較長。如啟動VS,Eclipse等,需要loading許多可能要的可能不要的,要等啊...

  • 懶漢式單例

優點:第一次使用時創建,不會一直占用資源,即延遲載入。

缺點:必須考慮多線程問題,特別是單例類作為資源控制器時,會涉及資源初始化,也會耗費許多時間,也會出現多線程同時首次引用此類,造成擁堵,導致系能性能降低

 

  •  單例模式的優缺點和適用環境

  •  單例模式的優點
  1. 提供唯一實例的受控訪問,可以嚴格控制何時訪問
  2. 由於只存在一個對象,可以節省系統資源
  3. 如果將單例模式的實例數目變為可變,即將單例模式進行擴展,即可獲得指定數目的實例對象,即節省資源,又提高效率(相當於多例類)
  • 單例模式的缺點
  1. 沒有抽象層,擴展有較大困難
  2. 單例類職責過重,一定程度上違背了單一職責原則(單例類即提供業務方法,又提供了創建對象的方法(工廠方法),對象創建和對象本身耦合在了一起)
  3. C#、JAVA 擁有GC(自動垃圾回收機制) (可以去瞭解下) ,在實例化的對象長時間不被利用,會被誤認為垃圾進行自動銷毀,下次利用又要重新創建,導致共用的單例對象丟失(女朋友丟了可不好受啊..)
  • 單例模式的適用環境
  1. 在系統只要一個實例對象(man只要一個girlfriend)/(資源管理器).....
  2. 客戶調用類的單個實例只允許使用一個公共訪問點,除了該點外,不允許其他途徑來訪問實例

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.安裝 首先打開Bootstarp的官網:https://v3.bootcss.com 下載完成後,解壓壓縮包,把解壓後的文件導入pycham中 在HTML頁面中的style中導入bootstrap的css文件和js文件,建議導入min.css,體積更小 以我的文件路徑為例: 安裝完成 二.更改p ...
  • 1、#id 根據給定的ID匹配一個元素,如果選擇器中包含特殊字元,可以用雙斜桿(\\) 轉義 如: 查找ID 為 myDiv[bar] 的元素 HTML 代碼: jQuery 代碼: 結果: 2、element 根據給定元素名匹配所有元素 如: 查找一個 DIV 元素。 HTML 代碼: jQuer ...
  • 自學前端開始,我對meta標簽接觸不多,主要把精力都集中在能顯示出來的標簽上,比如span、button、h1等等。有時候去查看一些知名網站的源碼,發現head標簽里有一大摞的meta。 今天就來學習一下meta的用處,看看有些啥屬性。 一、定義及作用 meta,即元數據(Metadata)是數據的 ...
  • 摘要: 理解JS執行原理。 原文: "JavaScript是如何工作的:引擎,運行時和調用堆棧的概述!" 作者: "前端小智" "Fundebug" 經授權轉載,版權歸原作者所有。 本文是旨在深入研究JavaScript及其實際工作原理的系列文章中的第一篇:我們認為通過瞭解JavaScript的構建 ...
  • 一、說說你對html語義化的理解? 答:1、去掉或者丟失樣式的時候能夠讓頁面呈現出清晰的結構 2、有利於SEO:與搜索引擎建立良好的溝通,有助於爬蟲抓取更過的有效信息,因為爬蟲依賴標簽來確定上下文和各個關鍵字的權重 3、方便其他設備解析,例如屏幕閱讀器,盲人閱讀器,移動設備 4、便於團隊開發和維護, ...
  • 前言 最近在用vue做移動端項目,網上找了一些移動端適配的方案,個人覺得手淘團隊flexible.js還是比較容易上手,在這裡做下總結。 主體 flexible.js適配方案採用rem佈局,根據屏幕解析度大小不同,調整根元素html的font size,從而達到每個元素寬高自動變化,適配不同屏幕 1 ...
  • 整體思路: 1.實現頁面佈局,設置css樣式 2.用jQuery獲取需要用到的變數 3.用jQuery為兩個按鈕綁定事件 一.頁面佈局: <style> body{ margin: 0 0 0 0; height: 1000px; width: 100%; } .d1{ position: abso ...
  • 如果第二次看到我的文章,歡迎右側掃碼訂閱我喲~ 👉 本文長度為4209字,建議閱讀12分鐘。 堅持原創,每一篇都是用心之作~ 在前一篇《360°全方位解讀「緩存」》中,我們聊了運用緩存的三種思路,以及在一個完整的系統中可以設立緩存的幾個位置,並且分享了關於瀏覽器緩存、CDN緩存、網關(代理)緩存的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...