【23種設計模式】單例模式(一)

来源:https://www.cnblogs.com/wml-it/archive/2023/08/26/17659188.html
-Advertisement-
Play Games

## 前言: 單例模式是創建型模式5種中的第1種,**關註對象的創建, 保證一個類僅有一個實例,並且提供一個全局訪問點**。在軟體系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個實例,才能確保它們的邏輯正確性、以及良好的效率。如何繞過常規的構造器,提供一種機制來保證一個類只創建一個實例 ...


前言:

  單例模式是創建型模式5種中的第1種,關註對象的創建, 保證一個類僅有一個實例,並且提供一個全局訪問點。在軟體系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個實例,才能確保它們的邏輯正確性、以及良好的效率。如何繞過常規的構造器,提供一種機制來保證一個類只創建一個實例?

一、應用場景:

  • 要求生產唯一序列號。
  • WEB 中的計數器,比如不用每次刷新都在資料庫裡加一次,用單例先緩存起來。
  • 創建的多個對象需要消耗的資源過多,比如 I/O 與資料庫的連接等。

二、創建與實現:

以下提供兩種情景實現方式,分別是單線程訪問和多線程訪問:

單線程實現:

定義:

 public class SingleObject
    {
        #region 第一種寫法

        /// <summary>
        /// 創建 SingleObject 的一個對象
        /// </summary>
        private static SingleObject instance = new SingleObject();

        /// <summary>
        /// 讓構造函數為 private,這樣該類就不會被實例化
        /// </summary>
        private SingleObject() { }


        /// <summary>
        /// 獲取全局唯一對象
        /// </summary>
        /// <returns></returns>
        public static SingleObject getInstance()
        {
            return instance;
        }

        #endregion

        #region 另外一種寫法
        /// <summary>
        /// 創建 SingleObject 的一個空對象
        /// </summary>
        private static SingleObject instance2  = null;
        /// <summary>
        /// 獲取全局唯一對象
        /// </summary>
        public static SingleObject getInstance2
        {
            get
            {
                if (instance == null)
                {
                    instance = new SingleObject();
                }
                return instance2;
            }
        }

        #endregion
        /// <summary>
        /// 單例中定義的方法
        /// </summary>
        /// <returns></returns>
        public string  showMessage()
        {
            return "這是單例設計模式返回的信息....";
        }
    }

全局單例訪問:

  //不合法的構造函數
    //編譯時錯誤:構造函數 SingleObject() 是不可見的
    //SingleObject object = new SingleObject();

    /// <summary>
    /// 獲取唯一可用的對象
    /// </summary>
    SingleObject object = SingleObject.getInstance();
 
    /// <summary>
    /// 調用返回消息
    /// </summary>
    string str =   object.showMessage();

說明:以上代碼在單線程情況下不會出現任何問題。但是在多線程的情況下卻不是安全的。如兩個線程同時運行到:

if (instance == null)

判斷是否被實例化,一個線程判斷為True後,在進行創建

instance = new Singleton();

之前,另一個線程也判斷(instance == null),結果也為True。這樣就就違背了Singleton模式的原則,保證一個類僅有一個實例。

多線程實現:

定義:

class Singleton
    {
        /// <summary>
        /// 請註意一個關鍵字volatile,如果去掉這個關鍵字,還是有可能發生線程不是安全的。
        /// </summary>
        private static volatile Singleton instance = null;
        /// <summary>
        ///創建一個靜態鎖
        /// </summary>
        private static object lockHelper = new object();
        private Singleton() { }
        public static Singleton getSingleton
        {
            get
            {
                if (instance == null)
                {
                    lock (lockHelper)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton();
                        }
                    }
                }
                return instance;
            }
        }
    }

說明:這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)。此程式對多線程是安全的,使用了一個輔助對象lockHelper,保證只有一個線程創建實例,如果instance為空,保證只有一個線程創建唯一的一個實例。

instance = new Singleton();

(Double Check)請註意一個關鍵字volatile,如果去掉這個關鍵字,還是有可能發生線程不是安全的。volatile 保證嚴格意義的多線程編譯器在代碼編譯時對指令不進行微調。

三、優缺點分析:

優點:

  • 在記憶體里只有一個實例,減少了記憶體的開銷,尤其是頻繁的創建和銷毀實例(比如管理首頁頁面緩存)。
  • 避免對資源的多重占用(比如寫文件操作)。

缺點:

  • 沒有介面,既不能繼承,又與單一職責原則衝突。一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。

本文來自博客園,作者:碼農阿亮,轉載請註明原文鏈接:https://www.cnblogs.com/wml-it/p/17659188.html


技術的發展日新月異,隨著時間推移,無法保證本博客所有內容的正確性。如有誤導,請大家見諒,歡迎評論區指正!
開源庫地址,歡迎點亮:
GitHub:https://github.com/ITMingliang
Gitee:   https://gitee.com/mingliang_it
GitLab: https://gitlab.com/ITMingliang

建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。



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

-Advertisement-
Play Games
更多相關文章
  • 問題代碼: 1 #include<windows.h> 2 #include<iostream> 3 #include<thread> 4 HANDLE h1; 5 HANDLE h2; 6 7 void CALLBACK test(PVOID a, BOOLEAN b) 8 { 9 std::co ...
  • ## IO 神器 Okio [官方](https://square.github.io/okio/) 是這麼介紹 Okio 的: > Okio is a library that complements java.io and java.nio to make it much easier to a ...
  • Python編程語言允許我們執行各種任務,所有這些都是在簡單模塊和短小精悍的代碼的幫助下完成的。在Python的幫助下進行屏幕截圖就是這樣一項任務。 Python為我們提供了許多模塊,使我們能夠執行不同的任務。有多種方法可以使用Python及其庫進行屏幕截圖。 ### 用Pyautogui模塊進行截 ...
  • 顧名思義,Python中的自動點擊器是一個簡單的Python應用程式,可以按照用戶的要求重覆點擊滑鼠。不同的參數,如速度、頻率和位置,可以根據用戶的要求進行改變。 Python有不同的模塊可用於控制鍵盤、滑鼠等設備。因此,我們可以使用這些模塊在Python中輕鬆創建一個自動點擊器。 本教程將展示在P ...
  • [TOC] spdlog是一個開源、跨平臺、無依賴、只有頭文件的C++11日誌庫,網上介紹的文章有很多這裡就不過多的介紹了,GitHub鏈接:[https://github.com/gabime/spdlog](https://github.com/gabime/spdlog)。 # 引用源碼 先下 ...
  • `fsnotify`是一個用Go編寫的文件系統通知庫。它提供了一種觀察文件系統變化的機制,例如文件的創建、修改、刪除、重命名和許可權修改。它使用特定平臺的事件通知API,例如Linux上的inotify,macOS上的FSEvents,以及Windows上的ReadDirectoryChangesW。 ...
  • 工具提示即 Tool Tip,當用戶把滑鼠移動到某個UI對象上並懸停片刻,就會出現一個“短小精悍”的視窗,顯示一些說明性文本。一般就是功能描述,讓用戶知道這個XX是幹啥用的。 在 Qt 中使用工具提示最方便的做法是直接用 QWidget 類的成員方法:setToolTip。從 QWidget 類派生 ...
  • # 什麼是主席樹 主席樹這個名字看上去很高級,其實不然,它還有另一個名字——可持久化線段樹。 ## 什麼是可持久化 可持久化顧名思義就是它可以變得~~**持久**~~,就是我們對他不斷進行單點修改後,突然查詢它的某一個歷史版本,這就叫可持久化。 # 引入例題 [洛谷3919:可持久化數組](http ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...