最近比較比較清閑,復習了下設計模式中的單例模式,對於單例模式,網上有很多實例,但是看來看去,很多感覺老是差點什么,當然也有比較多的寫的很好,所以決定自己動手練習下,順便記錄下,就當記筆記了。
在實際的開發中,幾乎每個項目都使用到單例模式,因為很多時候,一個類只能創建一個對象,即存在唯一實例,單例就是最恰當的解決辦法了。下面就分為在單線程中和多線程的來記錄吧!
在單線程中,網上有很多懶漢模式,餓漢模式什么的,這些可以自己去百度,就說下我自己比較常用的一種,直接上代碼比較直觀:
class CSingletonTwo { private: CSingletonTwo(){}//構造函數私有 public: static CSingletonTwo& getInstance(void); void init(void) { qDebug()<<" Test CSingletonTwo.........."; } }; CSingletonTwo& CSingletonTwo::getInstance() { static CSingletonTwo instance; return instance; }
這種方法(前提單線程中使用這個單例)我感覺是比較簡單明了的一種,網上還有一些用下面方法實現,但感覺還是不如上面的簡單明了(當然,各有的想法,蘿卜青菜,各有所愛。),如:
class singleton { protected: singleton(){} private: static singleton* p; public: static singleton* instance(); }; singleton* singleton::p = NULL; singleton* singleton::instance() { if (p == NULL) p = new singleton(); return p; }
多線程安全模式,用到了Qt的原子指針和C++模板,具體如下:
#include <QCoreApplication> #include <QAtomicPointer> #include <QReadWriteLock> #include <QMutex> #include <qDebug> template<class T> class CSingleton { private: CSingleton();//防止構造函數 CSingleton(const CSingleton<T> &);//防止拷貝構造函數 CSingleton<T>& operator=(const CSingleton<T>&);//防止賦值拷貝構造函數 QReadWriteLock m_internalMutex;//讀寫鎖 static QMutex m_mutex;//互斥鎖 static QAtomicPointer<T> m_instance;//實例 public: static T& getInstance(void);//獲取唯一實例 }; template<class T> QMutex CSingleton<T>::m_mutex(QMutex::Recursive);//一個線程可以多次鎖同一個互斥量 template<class T> QAtomicPointer<T>CSingleton<T>::m_instance;//原子指針,默認初始化是0 template<typename T> T& CSingleton<T>::getInstance(void) { #ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE if(!QAtomicPointer<T>::isTestAndSetNative())//運行時檢測 #endif { QMutexLocker locker(&m_mutex);//互斥鎖 if(m_instance.testAndSetOrdered(0, 0))//第一次檢測 { m_instance.testAndSetOrdered(0, new T);//第二次檢測 } return *m_instance.load(); } } class CTest { public: CTest(){} void init(void) { qDebug()<<" Test singteon!!!!!!!!!!"; } }; typedef CSingleton<CTest> test;//這里使用CTest來實例化這個模板,還可以自己定義其他類了來實例化,省去在每個使用單例的類中都實現一個單例的麻煩了
上面的多線程模式及其原子操作,參考了:https://www.cnblogs.com/codingmylife/archive/2010/07/14/1777409.html,但是在這基礎上加入了模板來實現,使用多種類型。我看網上也有使用繼承來達到單例適用多個類型,那樣也沒有不好,只是代碼比較繁瑣,倒不如使用模板來的爽快。
下面是測試代碼:
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); test::getInstance().init(); CSingletonTwo::getInstance().init(); return a.exec(); }
下面是在Qt5.3.2上測試的輸出: