在整個進程中,或者說是在整個工做過程當中,只容許有一個實例對象的存在 。這個實例對象可以完成所有工做過程所須要的屬性和方法。因此不須要再有其餘的實例!這個單例模式每每運用在某些資源受限的場景 中,和操做系統的 「互斥信號量」 很是類似。好比打印機,咱們限定只有一臺打印機(資源受限),而後就得防止其餘人另外開闢資源來實例化第二個打印機(能夠理解爲大家的資金只預算了這一臺打印機,若是超預算,你得破產!)。而且這個資源不光是給一我的使用的,它是一個全局的訪問點 !而且 一個類只能有這一個實例!ios
這個問題咱們分解成幾個小的問題來看:c++
實例如何而來?在面向對象編程中,對象實例所有來自構造方法,因此只須要隱藏構造方法 ,讓其餘用戶沒法去自行實例化便可。那麼這個實例就會是屬於這個類的通常實例 。既然這個實例是屬於類的,那麼說明這個實例是一個靜態成員 !程序員
只須要開放一個靜態接口(由於實例也是靜態的)。這個接口負責檢查實例是否已經被建立,如若被建立就直接返回已經存在的實例,不然實例化一個給屬於類的私有單例。編程
#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; }
這是一種典型的《懶漢模式》的實現方式,由於這個單例,是在第一次使用到的時候纔去初始化的!若是是《餓漢模式》,則是在尚未須要使用單例的時候就已經完成初始化了!其實要想實現《餓漢模式》很是簡單,只須要把咱們的單例從一個對象指針變成一個靜態的成員變量便可!以下:設計模式
#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++程序員!咱們該如何處理進程結束後的單例資源呢?框架
錯誤代碼以下: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; }
衆所周知,靜態對象,在發生類建立的進程 結束後,會系統自動回收資源,這個資源的回收也是調用了靜態對象的析構方法!因而咱們能夠利用這個特色,讓一個單例伴隨一個靜態對象,如何才能實現這點呢?只須要寫一個內部類,建立一個內部類對象,這個對象是和成員屬性、成員方法同級別的,是屬於外部類的實例的!也就是屬於單例的一個伴隨對象!咱們只須要讓這個對象成爲一個靜態對象,那麼就能夠在實例工做結束後,在它的析構中完成對實例的析構!
#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; }
本人也沒有在課堂上學過《設計模式》,也是在課餘時間裏作項目遇到了。深感設計模型、面向對象思想,在大型軟件設計中的做用!他們都能大大提升代碼的可複用性,減少工做量、減少代碼冗餘,增長軟件的穩定性!因爲沒有正式學習設計模式,因而本文標題也只敢寫:《初始設計模式》,寫的不對或者很差的地方,還請各位前輩大佬提出,歡迎指正!!!!