主頁 > 軟體設計 > 淺談C++設計模式--單例模式

淺談C++設計模式--單例模式

2020-09-23 01:09:00 軟體設計

單例模式(Singleton)[分類:創建型] [目的:為程式的某個類的訪問,提供唯一物件實體]

這估計是設計模式里面最簡單的一個類了,下面我們一起看看,單例它是什么?以及如何實作一個單例

  • 基本定義
    • 保證一個類僅有一個實體,并提供一個訪問它的全域訪問點.
  • 個人理解
    • 就是一個類在整個程式里面,有且僅有一個實體,這個實體由該類自己負責創建和保存,這樣保證它不會在任何其他地方被創建,必須提供一個訪問這個實體的全域訪問介面.
    • 那么有些人可能有疑問,為什么不直接用一個全域變數來控制外部對它的訪問呢?在這里如果用全域變數來控制外部的訪問它實際上還是不能避免你實體化多個物件,這樣還是達不到單例有且僅有一個實體的目的,
  • 單例的特征
    1. 有且僅有一個實體
    2. 實體必須由自己創建和保存
    3. 要提供和給外部訪問實體的介面
  • UML結構圖

 

  • 從UML結構圖中我們可以一步步實作出以下代碼
  • 簡單版本的單例模式
 1 class Singleton
 2 {
 3 public:
 4     static Singleton& GetInstance() 
 5     {
 6         static Singleton instance;
 7         return  instance;
 8     }
 9 private:
10     Singleton();
11 
12 };
  • 這里我們可以看到,這個版本建構式被私有化了,因此外部無法直接呼叫單例的構造器,而且使用靜態的區域變數做回傳,這樣不需要考慮對記憶體的管理,是不是非常方便!但是我們在對函式執行以下操作時
1 Singleton instance1=Singleton::GetInstance(); 
2 Singleton instance2=Singleton::GetInstance();
3 qDebug()<<"instance1 address:"<<&instance1;
4 qDebug()<<"instance2 address:"<<&instance2;
  • 我們運行程式看結果

  •  在這里instance1和instance2實體他們的地址是完全不同的.這樣的做法是不可取的,不是真正的單例,那么如何避免這樣的問題的?跟開發者說你們直接呼叫GetInstance介面就行,
  • NONONO....
  • 下面我們看看修改版本的單例看看 
 1 class SingletonModify
 2 {
 3 public:
 4     static SingletonModify& GetInstance() 
 5     {
 6         static SingletonModify instance;
 7         return  instance;
 8     }
 9     void sayHello();
10 private:
11     SingletonModify();
12     SingletonModify(SingletonModify const &);//to use this modify wrong demo
13     SingletonModify& operator =(SingletonModify const &);//to use this modify wrong demo
14 };
  • 從上面我們可以看出,我們重新定義了構造器以及=操作,這里不需要實作,然后我們再用相同的方式測驗看看,這下編譯器編譯不通過了,那我們想呼叫實體的方法或者操作實體怎么辦呢?
SingletonModify::GetInstance().sayHello();//after modify code,
  • 那我們只能通過上述方法訪問實體了,保證了實體的唯一性了,
  • 簡單版本的單例模式技術總結
  1. 將構造器私有化(保證外部無法創建實體) 
  2. 使用靜態的區域變數作為回傳(無需考慮記憶體管理的問題)
  3. 重新定義賦值運算子以及構造器.(避免=發生拷貝操作)
  • 是不是覺得到這里單例就已經差不多啦?并不是,我們使用的是C++,但是并沒有使用到C++的一個重要特征:指標
  • 首先我們針對上述簡單版本的單例模式再次進行修正,我們修改單例的函式回傳,用指標接收,看看下面代碼
 1 class SingletonSimplify
 2 {
 3 public:
 4     SingletonSimplify();
 5     static SingletonSimplify* GetInstanceptr()//simplify method
 6     {
 7         static SingletonSimplify instance;
 8         return  &instance;
 9     }
10 };
  • 測驗:
1 SingletonSimplify* instanceSmp1=SingletonSimplify::GetInstanceptr();//another simplify singleton method
2 SingletonSimplify* instanceSmp2=SingletonSimplify::GetInstanceptr();
3 qDebug()<<"instanceSmp1 address:"<<instanceSmp1;
4 qDebug()<<"instanceSmp2 address:"<<instanceSmp2;

 

 

  •  我們可以發現,用指標接收之后2個指標都是指向同一個地址,很好,這也是一種單例的實作方式,但是這個也屬于訪問靜態區域物件,還是沒有真正意義上使用到指標.再看看下面兩種方式
  1. 懶漢模式
    • 先看頭檔案.h代碼
      •  1 class SingletonLazyMode
         2 {
         3 public:
         4     static SingletonLazyMode* GetInstance();
         5     static void InstanceDispose();
         6     void sayHi();
         7 private:
         8     SingletonLazyMode();
         9     static SingletonLazyMode* mSingletonInstance;
        10     int num=10;
        11 };
    • .cpp實作
      •  1 SingletonLazyMode *SingletonLazyMode::mSingletonInstance=NULL;
         2 SingletonLazyMode *SingletonLazyMode::GetInstance()
         3 {
         4     if(mSingletonInstance==NULL)
         5     {
         6         mSingletonInstance=new SingletonLazyMode();
         7         mSingletonInstance->num=20;
         8     }
         9     return  mSingletonInstance;
        10 }
        11 void SingletonLazyMode::InstanceDispose()
        12 {
        13     if(mSingletonInstance!=NULL)
        14     {
        15         delete mSingletonInstance;
        16         mSingletonInstance=NULL;
        17     }
        18 }
        19 void SingletonLazyMode::sayHi()
        20 {
        21     qDebug()<<"hi lazy man! Number:"<<num;
        22 }
        23 SingletonLazyMode::SingletonLazyMode()
        24 {
        25 }
  2. 餓漢模式
    • 先看頭檔案.h代碼
      • 1 class SingletonEagerMode
        2 {
        3 public:
        4     static SingletonEagerMode* GetInstance();
        5     static void InstanceDispose();
        6 private:
        7     SingletonEagerMode();
        8     static SingletonEagerMode* mEagerInstance;
        9 };
    • .cpp實作
      •  1 SingletonEagerMode *SingletonEagerMode::mEagerInstance=new SingletonEagerMode();
         2 SingletonEagerMode *SingletonEagerMode::GetInstance()
         3 {
         4     return  mEagerInstance;
         5 }
         6 void SingletonEagerMode::InstanceDispose()
         7 {
         8     if(mEagerInstance!=NULL)
         9     {
        10         delete mEagerInstance;
        11         mEagerInstance=NULL;
        12     }
        13 }
        14 SingletonEagerMode::SingletonEagerMode()
        15 {
        16
        17 }
  • 測驗代碼
    •  1 SingletonLazyMode* lazyinstance1=SingletonLazyMode::GetInstance();//lazy mode 懶漢模式
       2     SingletonLazyMode* lazyinstance2=SingletonLazyMode::GetInstance();
       3     lazyinstance1->sayHi();
       4     lazyinstance2->sayHi();
       5     qDebug()<<"lazyinstance1 address:"<<lazyinstance1;
       6     qDebug()<<"lazyinstance2 address:"<<lazyinstance2;
       7     SingletonLazyMode::InstanceDispose();
       8     qDebug()<<"lazyinstance1 address:"<<lazyinstance1;
       9     qDebug()<<"lazyinstance2 address:"<<lazyinstance2;
      10     lazyinstance1->sayHi();
      11     lazyinstance2->sayHi();
      12     SingletonEagerMode* eagerinstance1=SingletonEagerMode::GetInstance();//eager mode 餓漢模式
      13     SingletonEagerMode* eagerinstance2=SingletonEagerMode::GetInstance();
      14     qDebug()<<"eagerinstance1 address:"<<eagerinstance1;
      15     qDebug()<<"eagerinstance2 address:"<<eagerinstance2;
  • 運行效果:
    • 這里我們可以看到不管是懶漢還是餓漢模式兩個實體的地址均是相同的,說明我們的單例是OK的
  • 技術總結: 
  • 下面對懶漢模式和餓漢模式經行對比分析其異同點:
    • 相同點:
      • 懶漢/餓漢模式實作結構基本類似
    • 不同點:
      • 懶漢模式初始化物件是在程式呼叫的時候,非執行緒安全,由于最終實作要加Qmutex進行枷鎖處理,執行效率會相對而言要低
      • 餓漢模式是程式啟動的時候就已經創建好了,浪費記憶體,但屬于執行緒安全,執行效率相對懶漢而言要高
  •  問題點:
  • 細心的同學可能發現了,在上面測驗程序中我呼叫了自己定義的Dispose介面,但是還是能再次呼叫lazyinstance1,lazyinstance2實體中的函式和變數???這是在MinGW編譯器下執行的結果,當我將編譯器換成MSVC時,顯示記憶體已經被釋放掉了
  • 下圖MSVC下的執行結果
  •  參考了一篇博客也沒看出什么問題:https://www.cnblogs.com/chengjundu/p/11283123.html

  • 如果有朋友知道望不吝賜教!!!!感謝,

  • 最后看看我們執行緒安全的懶漢實作方式

  •  .h檔案

     1 class SingletonThreadSafety
     2 {
     3 public:
     4     static SingletonThreadSafety* GetInstance();
     5     static void InstanceDispose();
     6 private:
     7     SingletonThreadSafety();
     8     static SingletonThreadSafety* mSaftyInstance;
     9     static QMutex mMutex;
    10 };
  • .cpp代碼
  •  1 SingletonThreadSafety *SingletonThreadSafety::mSaftyInstance=NULL;
     2 QMutex SingletonThreadSafety::mMutex;
     3 SingletonThreadSafety *SingletonThreadSafety::GetInstance()
     4 {
     5     if(mSaftyInstance==NULL)
     6     {
     7         QMutexLocker locker(&mMutex);
     8         if(mSaftyInstance==NULL)
     9         {
    10             mSaftyInstance=new SingletonThreadSafety();
    11         }
    12     }
    13     return  mSaftyInstance;
    14 }
    15 void SingletonThreadSafety::InstanceDispose()
    16 {
    17     if(mSaftyInstance!=NULL)
    18     {
    19         delete mSaftyInstance;
    20         mSaftyInstance=NULL;
    21     }
    22 }
    23 SingletonThreadSafety::SingletonThreadSafety()
    24 {
    25 
    26 }

    這就完美解決掉了執行緒安全問題,但是在獲取實體物件的時候需要對Qmutex進行判斷,這會損失一點點性能,

  • 以上就是對單例模式的完整概述
  • 下面進行全面的技術總結:
  • 在寫單例模式的時候我們要考慮到以下幾個方面:
  1. 要封閉默認的建構式,以防止多地方創建物件
  2. 類提供一個靜態的物件,用來保存該實體
  3. 提供一個公共的訪問實體的介面GetInstance
  4. 考慮執行緒安全問題

以上單例所有內容,如有錯誤請指出!!!

參考<<大話設計模式>>一書

附源代碼:

https://gitee.com/xiaochunlu/designer-pattern/tree/master/Singleton_Pattern

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/108315.html

標籤:設計模式

上一篇:最詳細的Spring和SpringMVC總結

下一篇:【資料結構與演算法】->演算法->拓撲排序-.如何確定代碼源檔案的編譯依賴?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more