1、先來談談什么是單例模式
這個單例模式說白了就一個句話:我是皇帝我獨苗
看看書上的定義:單例模式(Singleton Pattern)Ensure a class has only one instance, and provide a global point of access to it.(確保一個類只有一個實例,而且自行實例化並向整個系統提供這個實例)
使用場景:一個系統要求一個類只有且僅有一個對象,如果出現多個對象就會出現不良反應,可以采用單例模式
要求生成唯一序列號
在整個項目需要一個共享訪問點或共享數據
創建一個對象需要消耗的資源過多,如需要訪問IO和數據庫等資源
需要大量定義靜態常量和靜態方法(如工具類)的環境,當然也可以直接定義為static
2、實現思路:既然只能有一個實例,那我這個類里的構造函數就不能被隨便調用了,那我就把構造函數寫成私有的,這樣別人就不能調用了,接下來就該考慮我自己這個獨苗該怎么產生了,定義里面說到自行實例化,並且提供給整個系統,那我就用一個static 實例化一個實例,然后返回這個static實例。
3、考慮的問題
一個實例,整個系統使用,那線程同步問題就必須要考慮了。
為了解決這個問題:懶漢模式、餓懶漢模式、Meyers Singleton(目前最推薦的C++單例寫法)
4、代碼實現
//Meyers Singleton(目前最推薦的C++單例寫法)
#include <iostream> using namespace std; class Singleton { public: static Singleton& Instance() { static Singleton theSingleton; return theSingleton; } void doSomeThong(); private: Singleton(); ~Singleton(); }; Singleton::Singleton() { } Singleton::~Singleton() { } void Singleton::doSomeThong() { cout << "單例類" << endl; cout << "C++最推薦的單例類寫法" << endl; } int main() { Singleton::Instance().doSomeThong(); return 0; }
//懶漢模式:顧名思義,是一種典型的拖延(lazy)策略。當第一次要用單例類的時候,再產生實例 #include <iostream> using namespace std; class Singleton { public: ~Singleton(); //提供單例類的訪問方法 static Singleton* getInstance(); //提供刪除方法 static void deleteInstance(); void doSomething(); protected: Singleton();//構造方法定義為protect static Singleton* theSingleton; //單例類對象指針 }; Singleton* Singleton::theSingleton = nullptr;//講我們的單例對象指針初始化空 Singleton::Singleton() { } Singleton::~Singleton() { } Singleton* Singleton::getInstance() { if (!theSingleton) theSingleton = new Singleton(); return theSingleton; } void Singleton::deleteInstance() { if (theSingleton) { delete theSingleton; theSingleton = nullptr; } } void Singleton::doSomething() { cout << "懶漢模式" << "\n" << "單例模式" << endl; } int main() { Singleton::getInstance()->doSomething(); return 0; }
看這圖很顯然Singleton成為了一個單例類,但在這一塊我沒有解決線程安全問題,這個需要用到多線程的鎖機制
//餓漢模式 //餓漢模式與懶漢模式相反,是程序一開始就生成唯一實例。這樣就不用檢查是否存在實例,而且也無需考慮產生實例時的線程安全。 #include <iostream> using namespace std; class Singleton { public: ~Singleton(); //提供單例對象訪問 static Singleton& getInstance(); void doSomething(); protected: //構造函數聲明為 保護方法 Singleton(); //單例對象指針 static Singleton theSingleton; }; //提供單例類對象訪問 Singleton& Singleton::getInstance() { return theSingleton; } void Singleton::doSomething() { cout << "餓懶漢模式" << "\n" << "單例模式" << endl; } Singleton::Singleton() { } Singleton::~Singleton() {} int main() { Singleton::getInstance().doSomething(); return 0; }
//很不負責的把這段代碼放在這
5、優點
①由於單例模式在內存中只有一個實例,減少了內存開支,特別是一個對象需要頻繁創建銷毀時。
②減少系統性能開銷
③避免對資源的多重占用
④單例模式可以在系統設置全局訪問點,優化和共享資源訪問
6、缺點
①單例模式一般沒有接口,很難擴展,擴展基本必須修改源代碼
②對測試不友好,需要解決在並發中的問題
③單例模式與單一職責原則有沖突
參考書籍《設計模式之禪》