初識設計模式1:單例模式(不考慮多線程)

初識設計模式1:單例模式

一、什麼是單例模式?

在整個進程中,或者說是在整個工做過程當中,只容許有一個實例對象的存在 。這個實例對象可以完成所有工做過程所須要的屬性和方法。因此不須要再有其餘的實例!這個單例模式每每運用在某些資源受限的場景 中,和操做系統的 「互斥信號量」 很是類似。好比打印機,咱們限定只有一臺打印機(資源受限),而後就得防止其餘人另外開闢資源來實例化第二個打印機(能夠理解爲大家的資金只預算了這一臺打印機,若是超預算,你得破產!)。而且這個資源不光是給一我的使用的,它是一個全局的訪問點 !而且 一個類只能有這一個實例ios

二、如何實現單例模式?

這個問題咱們分解成幾個小的問題來看:c++

2.一、如何保證一個惟一的實例?

實例如何而來?在面向對象編程中,對象實例所有來自構造方法,因此只須要隱藏構造方法 ,讓其餘用戶沒法去自行實例化便可。那麼這個實例就會是屬於這個類的通常實例 。既然這個實例是屬於類的,那麼說明這個實例是一個靜態成員程序員

2.二、如何獲取這個惟一的實例?

只須要開放一個靜態接口(由於實例也是靜態的)。這個接口負責檢查實例是否已經被建立,如若被建立就直接返回已經存在的實例,不然實例化一個給屬於類的私有單例。編程

2.三、代碼示例:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "單一實例已經被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;

int main() {
	Singleton* instance1 = Singleton::GetMySingleInstance();
	Singleton* instance2 = Singleton::GetMySingleInstance();
	if (instance1 == instance2)
		cout << "這是一個單例模式!" << endl;
	else
		cout << "這不是一個單例模式!" << endl;
	return 0;
}

2.四、結果展現:

在這裏插入圖片描述

2.五、作個小結:

這是一種典型的《懶漢模式》的實現方式,由於這個單例,是在第一次使用到的時候纔去初始化的!若是是《餓漢模式》,則是在尚未須要使用單例的時候就已經完成初始化了!其實要想實現《餓漢模式》很是簡單,只須要把咱們的單例從一個對象指針變成一個靜態的成員變量便可!以下:設計模式

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton MySingleInstance;
	Singleton() { cout << "單一實例已經被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() { return &MySingleInstance; }
};
Singleton Singleton::MySingleInstance;// 餓漢模式,這個類一存在這個單例就被建立!

int main() {
	Singleton* instance1 = Singleton::GetMySingleInstance();
	Singleton* instance2 = Singleton::GetMySingleInstance();
	if (instance1 == instance2)
		cout << "這是一個單例模式(餓漢模式)!" << endl;
	else
		cout << "這不是一個單例模式!" << endl;
	return 0;
}

《餓漢模式》實現的單例模式運行結果以下:
在這裏插入圖片描述安全

那麼餓漢模式和懶漢模式在具體應用上有何區別呢?查閱資料得知有線程安全方面的問題,可是咱們這裏只是初探,就不研究線程安全了!我我的理解來講,線程安全應該相似於《操做系統》裏面互斥型信號量在同步訪問的時候的線程保護吧,我沒有仔細研究,若有說錯的地方,還請各位高手指出markdown

三、關於單例模式(懶漢)的資源回收問題

衆所周知,懶漢模式下實現的單例,須要依賴動態內存分配。這種分配在堆空間的資源,必定是須要程序員經過代碼來進行資源回收的!衆所周知,只有儘可能完美作到RAII原則的c++程序員纔是一個優秀的c++程序員!咱們該如何處理進程結束後的單例資源呢?框架

3.一、使用析構函數,自行delete釋放

錯誤代碼以下:ide

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "單一實例被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
	~Singleton() { 
		delete Singleton::MySingleInstance; 
		// delete 以後調用析構函數,而後析構函數又調用 delete … 循環往復!
		cout << "單例資源被釋放" << endl;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 餓漢模式,這個類一存在這個單例就被建立!

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	delete instance;
	return 0;
}

這種操做沒法完成析構,甚至還會陷入死循環帶來程序崩潰 !緣由我在上面的註釋裏寫到了:delete 以後調用析構函數,而後析構函數又調用 delete … 循環往復!函數

那是否這種調用析構函數的方式不可行呢?其實不是的!

如何避免這個已經被delete後的對象,再次進入屬於它的析構方法呢?只須要進行一次標記就好:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "單一實例被建立!" << endl; }
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
	~Singleton() { 
		if (nullptr != MySingleInstance) {// 檢測標記
			Singleton::MySingleInstance = nullptr;// 作上標記
			delete Singleton::MySingleInstance;
		}
		cout << "單例資源被釋放" << endl;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 餓漢模式,這個類一存在這個單例就被建立!

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	delete instance;
	return 0;
}

析構後效果展現:

在這裏插入圖片描述

3.二、可否讓系統自行在進程結束以後,完成單例資源的回收呢?

衆所周知,靜態對象,在發生類建立的進程 結束後,會系統自動回收資源,這個資源的回收也是調用了靜態對象的析構方法!因而咱們能夠利用這個特色,讓一個單例伴隨一個靜態對象,如何才能實現這點呢?只須要寫一個內部類,建立一個內部類對象,這個對象是和成員屬性、成員方法同級別的,是屬於外部類的實例的!也就是屬於單例的一個伴隨對象!咱們只須要讓這個對象成爲一個靜態對象,那麼就能夠在實例工做結束後,在它的析構中完成對實例的析構!

系統自動回收的代碼框架:

#include <iostream>
using namespace std;

class Singleton {
private:
	static Singleton* MySingleInstance;
	Singleton() { cout << "單一實例被建立!" << endl; }

	class GarbageCollector {
	public:
		~GarbageCollector() {
			if (nullptr != Singleton::MySingleInstance) {
				Singleton::MySingleInstance = nullptr;// 作上標記
				delete Singleton::MySingleInstance;
			}
			cout << "單例資源被釋放" << endl;
		}
	};
	static GarbageCollector MyGC;
public:
	static Singleton* GetMySingleInstance() {
		if (nullptr == MySingleInstance)
			MySingleInstance = new Singleton();
		return MySingleInstance;
	}
};
Singleton* Singleton::MySingleInstance = nullptr;// 餓漢模式,這個類一存在這個單例就被建立!
Singleton::GarbageCollector Singleton::MyGC;

int main() {
	Singleton* instance = Singleton::GetMySingleInstance();
	return 0;
}

系統自動回收單例資源的結果展現:

在這裏插入圖片描述

四、一個具體的應用場景:

假設須要對一個單例資源:打印機進行處於單例模式下的工做,個人代碼以下:

#include <iostream>
using namespace std;

class printing {
public:
	static printing* GetPrintingInstance() {
		if (nullptr == MyInstance)
			MyInstance = new printing();
		return MyInstance;
	}
	class Garbo {
	public:
		~Garbo(){
			if (nullptr != printing::MyInstance) {
				printing::MyInstance = nullptr;
				delete printing::MyInstance;
				cout << "打印機實例註銷" << endl;
			}
		}
	};
	static Garbo MyGarbo;
	static int number;
	void doPrint() { 
		cout << "打印機正在打印第:" << number << " 個打印任務" << endl; 
		number++;
	}
private:
	printing() { cout << "打印機實例啓動" << endl; }
	static printing* MyInstance;
};
int printing::number = 1;
printing* printing::MyInstance = nullptr;
printing::Garbo MyGarbo;// 默認構造,初始化 MyGarbo

void doIt() {
	printing* util = printing::GetPrintingInstance();
	int task = 20;
	while (task--) 
		util->doPrint();
}

int main() {
	doIt();
	return 0;
}

應用結果展現以下:

在這裏插入圖片描述

寫在後面的話:

本人也沒有在課堂上學過《設計模式》,也是在課餘時間裏作項目遇到了。深感設計模型、面向對象思想,在大型軟件設計中的做用!他們都能大大提升代碼的可複用性,減少工做量、減少代碼冗餘,增長軟件的穩定性!因爲沒有正式學習設計模式,因而本文標題也只敢寫:《初始設計模式》,寫的不對或者很差的地方,還請各位前輩大佬提出,歡迎指正!!!!

相關文章
相關標籤/搜索