1. 程式人生 > >c++設計模式——單例模式

c++設計模式——單例模式

單例模式,可以說設計模式中最常應用的一種模式了。但是如果沒有學過設計模式的人,可能不會想到要去應用單例模式,面對單例模式適用的情況,可能會優先考慮使用全域性或者靜態變數的方式,這樣比較簡單,也是沒學過設計模式的人所能想到的最簡單的方式了。

一個簡單的單例模式實現:

建構函式宣告為private或protect防止被外部函式例項化,內部儲存一個private static的類指標儲存唯一的例項,例項的動作由一個public的類方法代勞,該方法也返回單例類唯一的例項。

程式碼:

class Singleton 
{
private:
    Singleton(){}
    ~Singleton(){}
    static Singleton* instance;
public:
    Singleton* getInstance();
}

Singleton* instance = NULL;

Singleton* Singleton::getInstance() 
{
	if (instance == NULL) {
		instance = new Singleton();
	}
	return instance;
}
這是一個很棒的實現,簡單易懂。但這是一個完美的實現嗎?不!該方法是執行緒不安全的,考慮兩個執行緒同時首次呼叫instance方法且同時檢測到p是NULL值,則兩個執行緒會同時構造一個例項給p,這是嚴重的錯誤!同時,這也不是單例的唯一實現!


一般情況下,我們建立的一些類是屬於工具性質的,基本不用儲存太多的跟自身有關的資料,在這種情況下,每次都去new一個物件,即增加了開銷,也使得程式碼更加臃腫。其實,我們只需要一個例項物件就可以。如果採用全域性或者靜態變數的方式,會影響封裝性,難以保證別的程式碼不會對全域性變數造成影響。


考慮到這些需要,我們將預設的建構函式宣告為私有的,這樣就不會被外部所new了,甚至可以將解構函式也宣告為私有的,這樣就只有自己能夠刪除自己了。在Java和C#這樣純的面向物件的語言中,單例模式非常好實現,直接就可以在靜態區初始化instance,然後通過getInstance返回,這種就被稱為餓漢式單例類。也有些寫法是在getInstance中new instance然後返回,這種就被稱為懶漢式單例類,但這涉及到第一次getInstance的一個判斷問題。

單例大約有兩種實現方法:

懶漢與餓漢:

    懶漢:故名思義,不到萬不得已就不會去例項化類,也就是說在第一次用到類例項的時候才會去例項化,所以上邊的經典方法被歸為懶漢實現;
    餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行例項化。

特點與選擇:

由於要進行執行緒同步,所以在訪問量比較大,或者可能訪問的執行緒比較多時,採用餓漢實現,可以實現更好的效能。這是以空間換時間。
在訪問量較小時,採用懶漢實現。這是以時間換空間。

下面的程式碼只是表示一下,跟具體哪種語言沒有關係。

單執行緒中:

Singleton* getInstance( )
{
    if (instance == NULL) {
        instance = new Singleton( );
    }
    return instance;
}

這樣就可以了,保證只取得了一個例項。但是在多執行緒的環境下卻不行了,因為很可能兩個執行緒同時執行到if (instance == NULL)這一句,導致可能會產生兩個例項。於是就要在程式碼中加鎖。

Singleton* getInstance()
{
    lock();
    if (instance == NULL){
       instance = new Singleton();
    }
    unlock();
    return instance;
}

但這樣寫的話,會稍稍映像效能,因為每次判斷是否為空都需要被鎖定,如果有很多執行緒的話,就愛會造成大量執行緒的阻塞。於是又想出了雙重鎖定。

Singleton* getInstance()
{
    if (instance == NULL) {
	lock();
    	if (instance == NULL) {
       		instance = new Singleton();
    	}
    	unlock();
    }
    return instance;
}
這樣只夠極低的機率下,通過越過了if (instance == NULL)的執行緒才會有進入鎖定臨界區的可能性,這種機率還是比較低的,不會阻塞太多的執行緒,但為了防止一個執行緒進入臨界區建立例項,另外的執行緒也進去臨界區建立例項,又加上了一道防禦if (instance == NULL),這樣就確保不會重複建立了。

常用的場景

單例模式常常與工廠模式結合使用,因為工廠只需要建立產品例項就可以了,在多執行緒的環境下也不會造成任何的衝突,因此只需要一個工廠例項就可以了。

優點

1.減少了時間和空間的開銷(new例項的開銷)。
2.提高了封裝性,使得外部不易改動例項。

缺點

1. 懶漢式是以時間換空間的方式。

2. 餓漢式是以空間換時間的方式。

C++實現

//singleton.h

#ifndef UNTITLED1_SIMPLETON_H
#define UNTITLED1_SIMPLETON_H

class Singleton {
private:
    Singleton();
    Singleton(const Singleton&);  //把複製建構函式和=操作符也設為私有,防止被複制
    Singleton& operator=(const Singleton&);
    ~Singleton();

public:
    static Singleton *getInstance();
    static Singleton *instance;

};

#endif //UNTITLED1_SIMPLETON_H

//singleton.cpp

#include <cstdio>
#include "singleton.h"

Singleton* Singleton::instance = new Singleton();

Singleton::Singleton() {

}

Singleton::Singleton(const Singleton &){

}

Singleton& Singleton::operator=(const Singleton &) {

}

Singleton *Singleton::getInstance() {
    return instance;
}

//main.cpp

#include <iostream>
#include "singleton.h"

using namespace std;

int main() {
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();
    if (singleton1 == singleton2) {
        cout << "singleton model" << endl;
    }
    return 0;
}
//輸出:
singleton model

相關推薦

設計模式——模式(C++)

clu win 安全 iostream public size turn instance stat 一: 餓漢式單例: 靜態區初始化instance,然後通過getInstance返回。這種方式沒有多線程的問題,是一種以空間換時間的方式,不管程序用不用,都會構造唯一的

C#設計模式--模式

資源 let readonly eat 私有靜態變量 sta 技術分享 span ret 目的:避免對象的重復創建 單線程具體的實現代碼 /// <summary> /// 私有化構造函數 /// </summary>

C++設計模式-模式

con git god www light nullptr return post gpo 版權聲明:若無來源註明,Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址: 本文標題:C++設計模式-單例模式 本文地址:http://techieli

C#設計模式——模式

code 關閉 object 需要 rm2 學習 single C# oid 一、單例模式定義: 確保一個類只有一個實例,並提供一個訪問它的全局訪問點。 二、背景: 當我們的系統中某個對象只需要一個實例的情況,例如:操作系統中只能有一個任務管理器,操作文件時,同一時間內只允

C#設計模式 —— 模式

  嗯,這是本人的第一篇隨筆,就從最簡單的單例模式開始,一步一步地記錄自己的成長。   單例模式是最常見的設計模式之一,在專案程式碼中幾乎隨處可見。這個設計模式的目的就是為了保證例項只能存在一個。單例模式往下還能再細分為懶漢模式和餓漢模式。下面逐個來看。 1.餓漢模式   餓漢模式的做法是在類載入的時候

設計模式-模式-C++實現

單例模式:保證一個類提供且僅提供一例項,並提供一個訪問它的全域性訪問點。 場景: 1.當類只能有一個例項並且客戶可以從一個公共的介面訪問到例項; 2.當這個唯一的例項應該是通過子類化可擴充套件的,並且客戶應該無需更改程式碼就能使用一個擴充套件的例項。 #include <s

C#設計模式-模式

單例模式就是保證在整個應用程式的生命週期中,在任何時刻,被指定的類只有一個例項,併為客戶程式提供一個獲取該例項的全域性訪問點 一:經典模式: using System; using System.Collections.Generic; using System.Li

設計模式——模式C++實現)

一、單例模式定義: 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享。 二、應用場景: 比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些配置

c++設計模式——模式

單例模式,可以說設計模式中最常應用的一種模式了。但是如果沒有學過設計模式的人,可能不會想到要去應用單例模式,面對單例模式適用的情況,可能會優先考慮使用全域性或者靜態變數的方式,這樣比較簡單,也是沒學過設計模式的人所能想到的最簡單的方式了。一個簡單的單例模式實現:建構函式宣告為

設計模式C++實現 1.模式

單例模式即實現單例類,即系統中一個類只有一個例項,而且該例項易於外界訪問。這樣方便對例項個數進行控制並節約系統資源。 而單例常用與一些非區域性靜態物件,對於這些物件,程式難以控制,對於這些存在與全域性,且一般持久存在的物件,有時需要按照一定約束或順序來進行初始化,而初始化這

設計模式——模式C++實現

引出問題: 設計一個類,我們只能生成該類的一個物件例項。 不好的解法:只適用於單執行緒環境 因為該類只能生成一個物件例項,那麼該類的建構函式必須是私有的,從而避免他人建立例項。在需要的時候建立該類的一個物件。 下面是程式實現: /****************

[轉]設計模式--模式(一)懶漢式和餓漢式

打印 是否 調用構造 餓漢 一段 tools 會有 輸出結果 java 單例模式是設計模式中比較簡單的一種。適合於一個類只有一個實例的情況,比如窗口管理器,打印緩沖池和文件系統, 它們都是原型的例子。典型的情況是,那些對象的類型被遍及一個軟件系統的不同對象訪問,因此需要一個

javascript設計模式-模式

空間 spa 靜態變量 通過 script 無法 單例 onf 訪問 單例模式,是創建型設計模式的一種,又被稱為單體模式,是只允許實例化一次的對象類。有時也用來規劃一個命名空間。 1 var Util = { 2 getName: function () {

設計模式--模式

final 簡單 封裝 產生 非線程安全 span 操作 ati zed 單例設計模式 Singleton是一種創建型模式,指某個類采用Singleton模式,則在這個類被創建後,只可能產生一個實例供外部訪問,並且提供一個全局的訪問點。 核心知識點如下: (1) 將采用單例

設計模式——模式

pre hostname turn cin user order 總結 -type path_info 單例模式 實例:web應用程序 #!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server impor

設計模式-模式

java return 全局對象 實例化 urn ole col scrip 獨立   單例,即一個對象只有一個實例,即使實例化多次,拿到的也是同一個實例。   JavaScript中,全局對象就是單例,如:window、document;獲取的DOM也是單例的。   單例

PHP面向對象-設計模式 模式 簡單工廠模式 工廠方法模式

單例 nbsp 私有化 {} 意義 pan php代碼 get fun 1.單例模式   單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例。即一個類只有一個對象實例。   要實現每一個類只有一個實例

PHP模式設計模式、工廠模式、註冊樹模式、適配器模式、觀察者模式

操作符 unset 關系 玩具 ati ase color 只有一個 bsp php模式設計之單例模式   什麽是單例模式?   單例模式是指在整個應用中只有一個實例對象的設計模式   為什麽要用單例模式?   php經常要鏈接數據庫,如果在一個項目中頻繁建立連接數據庫,會

[設計模式]模式

釋放 常用 覆寫 這樣的 訪問 客戶端瀏覽器 創建 article net 引言 做為已經開發9年多的我,最近感覺有點迷茫,技術更新太快,有點跟不上這麽快的節奏,在開始工作時,一直也聽領導說23種設計模式,當時也看了視頻,看完也沒有太大的收獲,在工作中有的時候也是為了把設計

C++再論模式

proc .text pro auto -c com hide lock views #include <iostream> #include <windows.h> #include <mutex> std::mut