【設計模式】單例模式【代碼】

單例模式

目錄

單例模式

1、懶漢式

2、餓漢式

3、測試


  • 目的:主要解決一個全局使用的類頻繁的創建和銷燬的問題
  • 實現:保證一個類只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法
  • 三要素:(1)構造函數私有化;(2)靜態函數,用來獲取單例;(3)有一個靜態的自身變量成員,用來返回單例對象
  • 分類:(1)懶漢式:通過單例函數來獲取單例,單例函數中創建對象時,需判斷對象是否存在;(2)餓漢式:不通過調用單例函數來獲取對象,而是直接在類外部new一個對象,即定義全局變量。
  • 注意:懶漢式會出現多線程問題。解決:雙重鎖機制實現線程安全。
  • 使用場景:創建的一個對象需要消耗的資源過多,比如I/O與數據庫的連接等。

1、懶漢式

//懶漢式
class LanHanShi
{
public:
	static LanHanShi* GetObject()
	{
		if (lhs == NULL)  //判斷對象是否已存在,保證只初始化一個對象
		{
			lhs = new LanHanShi;
			/*
			若在多線程中,構造函數中有sleep(100);則有多個線程時,在每個線程
			創建對象進入這個函數時,會首先判斷對象是否已存在,而由於此線程
			停留在構造函數中還未返回,所以對象還未創建,另一個線程也將進入構造
			函數中,所以此時會創建多個對象,則不再是單例模式。
			*/
		}
		/*解決懶漢式與多線程的問題方法:
		if(lhs==NULL)  //第一次檢查保證所有線程進來之前的判斷
		{
			cs.lock();    //可能到這一步,有好幾個線程進來
			if(lhs==NULL) //第二次檢查,保證在有一個線程已進來創建對象後,
			{             //防止其他線程進來再次創建對象
				lhs = new LanHanShi;
			}
			cs.unlock();  //加鎖部分爲臨界區
		}
		*/
		
		return lhs;
	}

~LanHanShi()
	{
		if (lhs != NULL)
		{
			delete lhs;
			lhs = NULL;
			cout << "~LanHanShi()" << endl;
		}
	}
private:
	LanHanShi()
	{
		cout << "LanHanShi()" << endl;
	}
	
private:
	static LanHanShi *lhs;
};

LanHanShi* LanHanShi::lhs = NULL;  //靜態類型需要在外部定義
//定義格式:(不加static)類型 類名::變量名=初始化值

2、餓漢式

class EHanShi
{
public:
	static EHanShi* GetObject()  //函數中有靜態變量,則函數必須是靜態函數
	{
		return ehs;
	}
private:
	EHanShi()
	{
		cout << "EHanShi()" << endl;
	}
private:
	static EHanShi *ehs;
};

EHanShi* EHanShi::ehs = new EHanShi;  //餓漢式直接在類外部進行new對象
//這句話是在調用函數之前就被執行,爲全局變量

void EHanShiDisplay()
{
	EHanShi *p1 = EHanShi::GetObject();
	EHanShi *p2 = EHanShi::GetObject();
}

void LanHanShiDisplay()
{
	//懶漢式即只在GetObject執行時纔會獲取單例
	LanHanShi *p1 = LanHanShi::GetObject();
	LanHanShi *p2 = LanHanShi::GetObject();
	//確實構造函數只執行了一次,創建了一個單例
	//單例生命週期和類一樣,不會執行析構函數
}

3、測試

int main1()
{
	LanHanShiDisplay();
	EHanShiDisplay();
	//構造函數都只被執行了一次,爲單例模式,懶漢式有多線程問題,而餓漢式沒有
	system("pause");
	return 0;
}

結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章