【設計模式】單例模式的三種形式 C++ 創建型模式

單例模式顧名思義就是隻能生成一個示例。其實在我個人不太成熟的理解上來說,單例模式的作用等同於在所有的成員變量和成員類前面加上一個“static”。所有調用這個類生成的實例都是同一個,因此我認爲等同於將所有的類資源變成靜態資源。

既然要有且僅有生成一個實例,那麼我們需要做的就兩件事。

1.將所有能夠生成類實例的途徑全部堵上,例如構造函數、拷貝構造函數私有化,外部無法訪問也就無法通過他們生成實例了。

2.既然無法在外部生成類的實例,那麼我們就需要想辦法在類的內部生成類的實例,並且能夠被我們所調用。

綜上所訴,就可以得到一個簡單的單例模式的例子了:

#include <iostream>
#define debug
class Single{
	private:
		Single(){
			this->test = 0;
		}
		Single(const Single&){;}
		Single& operator = (const Single&){;}
		static Single* instance;
	public:
		static Single* getInstance();
		int test;
};

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

int main(){
	Single* single_1 = Single::getInstance();
	Single* single_2 = Single::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1與single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
}

運行結果:

爲了說明單例模式是成功的,代碼先比較了“兩個實例”的地址,程序輸出結果表明地址是一致的。我們還在下面先後修改了single_1和Single_2實例中test的值,輸出結果表明,sing_1和sing_2中test的值始終保持一致,也證明了僅生成了一個實例。

單例模式中還有一種稱作是餓漢單例模式的分類,餓漢單例模式簡單粗暴,在類內部直接生成一個實例,封堵其餘生成實例的途徑,以下是例子:

#include <iostream>
#define debug
class Single_hunger{
	private:
		Single_hunger(){
			this->test = 0;
		}
		Single_hunger(const Single_hunger&){;}
		Single_hunger& operator = (const Single_hunger&){;}
		static Single_hunger* instance;
	public:
		static Single_hunger* getInstance();
		int test;
};

Single_hunger* Single_hunger::instance = new Single_hunger();
Single_hunger* Single_hunger::getInstance(){
	return instance;
}

int main(){
	Single_hunger* single_1 = Single_hunger::getInstance();
	Single_hunger* single_2 = Single_hunger::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1與single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
}

可以看出,餓漢單例和普通的單例模式的區別在於,普通單例的實例是在getInstance()函數中生成的,當且僅當訪問這個函數的時候纔會生成實例;而餓漢模式是在類的內部實現的,因此一開始就已經存在了這個實例,因此,餓漢模式的調用速度和反應速度更快,但是資源利用效率和系統加載時間上就表現比較差了。

同時,餓漢單例模式無需考慮多線程的影響,如果系統採用了多線程,那麼普通的單例模式就不能滿足系統的需求了。因爲我們要創建實例,在多線程訪問的情況下,我們需要加鎖,這種模式叫懶漢模式,一下是例子:

#include<iostream>
#define debug
class Single_lazy{
	private:
		Single_lazy(){
			this->test = 0;
		}
		static Single_lazy* instance;
		Single_lazy(const Single_lazy&){;}
		Single_lazy& operator = (const Single_lazy&){;}
		static bool lock;
		
	public:
		int test;
		static Single_lazy* getInstance();
};
Single_lazy* Single_lazy::instance = NULL;
bool Single_lazy::lock = false;
Single_lazy* Single_lazy::getInstance(){
	if(instance == NULL){
		/* 沒有生成示例,首先上鎖 */
		if(!lock){
			lock = true;
			/* 第二次檢測是否已經生成示例 */
			if(instance == NULL){
				instance = new Single_lazy();
			}else;
			lock = false;
		}else; 
	}else;
	return instance;
}

int main(){
	Single_lazy* single_1 = Single_lazy::getInstance();
	Single_lazy* single_2 = Single_lazy::getInstance();
	
	if(single_1 == single_2)
		std::cout << "single_1與single_2的地址一致" << std::endl << std::endl;
	
	#ifdef debug
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_1->test = 5;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	single_2->test = 10;
	std::cout << "single_1:" << single_1->test << std::endl;
	std::cout << "single_2:" << single_1->test << std::endl << std::endl;
	
	#endif
	std::cin.get();
	return 0;
} 

懶漢模式在原有的普通單例模式的基礎上增加了鎖,保證有且僅有一個線程能夠創建實例,避免了多線程導致創建多個實例出來。

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