下面,对 单例的模版实现
使用宏进一步简化。
Singleton.h
在 Singleton.h 的最后面添加宏 SINGLETON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #ifndef SINGLETON_H #define SINGLETON_H
#include <QMutex> #include <QScopedPointer>
template <typename T> class Singleton { public: static T& getInstance();
Singleton(const Singleton &other) = delete; Singleton<T>& operator=(const Singleton &other) = delete;
private: static QMutex mutex; static QScopedPointer<T> instance; };
template <typename T> QMutex Singleton<T>::mutex; template <typename T> QScopedPointer<T> Singleton<T>::instance;
template <typename T> T& Singleton<T>::getInstance() { if (instance.isNull()) { mutex.lock(); if (instance.isNull()) { instance.reset(new T()); } mutex.unlock(); }
return *instance.data(); }
#define SINGLETON(Class) \ private: \ Class(); \ ~Class(); \ Class(const Class &other) = delete; \ Class& operator=(const Class &other) = delete; \ friend class Singleton<Class>; \ friend struct QScopedPointerDeleter<Class>; \ \ public: \ static Class& instance() { \ return Singleton<Class>::getInstance(); \ }
#endif
|
ConfigUtil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #ifndef CONFIGUTIL_H #define CONFIGUTIL_H
#include "Singleton.h" #include <QString>
class ConfigUtil { SINGLETON(ConfigUtil)
public: QString getDatabaseName() const; };
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include "ConfigUtil.h" #include <QDebug>
ConfigUtil::ConfigUtil() { qDebug() << "ConfigUtil()"; }
ConfigUtil::~ConfigUtil() { qDebug() << "~ConfigUtil()"; }
QString ConfigUtil::getDatabaseName() const { return "Pirate"; }
|
现在实现单例的类,单例相关的代码,只需要:
- [1] 包含头文件
Singleton.h
- [2] 使用宏
SINGLETON
- [3]、[4] 实现构造函数和析构函数,因为它们已经在宏 SINGLETON 里被声明为 private 的了,所以必须实现
在 单例的智能指针+宏的实现
里用了两个宏,这里只用了一个,也算是个进步吧。
main.cpp
main()
函数用于演示 ConfigUtil 的使用:
1 2 3 4 5 6 7 8 9
| #include "ConfigUtil.h" #include <QDebug>
int main(int argc, char *argv[]) { qDebug() << ConfigUtil::instance().getDatabaseName(); qDebug() << Singleton<ConfigUtil>::getInstance().getDatabaseName();
return 0; }
|
输出:
ConfigUtil()
“Pirate”
“Pirate”
~ConfigUtil()
通过上面对代码的优化,使用模版和宏,实现了大量代码的复用,只需要简单的几条语句,就能实现一个单例的类,让我们把更多的精力放在类的业务逻辑上,而不是浪费在单例实现的那些模版代码上。