單例模式,能夠說設計模式中最常應用的一種模式了,聽說也是面試官最喜歡的題目。可是若是沒有學過設計模式的人,可能不會想到要去應用單例模式,面對單例模式適用的狀況,可能會優先考慮使用全局或者靜態變量的方式,這樣比較簡單,也是沒學過設計模式的人所能想到的最簡單的方式了。html
通常狀況下,咱們創建的一些類是屬於工具性質的,基本不用存儲太多的跟自身有關的數據,在這種狀況下,每次都去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.提升了封裝性,使得外部不易改動實例。spa
1.懶漢式是以時間換空間的方式。線程
2.餓漢式是以空間換時間的方式。設計
#ifndef _SINGLETON_H_ #define _SINGLETON_H_ class Singleton{ public: static Singleton* getInstance(); private: Singleton(); //把複製構造函數和=操做符也設爲私有,防止被複制 Singleton(const Singleton&); Singleton& operator=(const Singleton&); static Singleton* instance; }; #endif
#include "Singleton.h" Singleton::Singleton(){ } Singleton::Singleton(const Singleton&){ } Singleton& Singleton::operator=(const Singleton&){ } //在此處初始化 Singleton* Singleton::instance = new Singleton(); Singleton* Singleton::getInstance(){ return instance; }
#include "Singleton.h" #include <stdio.h> int main(){ Singleton* singleton1 = Singleton::getInstance(); Singleton* singleton2 = Singleton::getInstance(); if (singleton1 == singleton2) fprintf(stderr,"singleton1 = singleton2\n"); return 0; }
1 g++ -o client Singleton.cpp client.cpp