Content Table

单例的模版+宏的实现

下面,对 单例的模版实现 使用宏进一步简化。

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;
};

/*-----------------------------------------------------------------------------|
| Singleton Implementation |
|----------------------------------------------------------------------------*/
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()); // 此指针会在全局变量作用域结束时自动 deleted (main 函数返回后)
}
mutex.unlock();
}

return *instance.data();
}

/*-----------------------------------------------------------------------------|
| Singleton Macro |
|----------------------------------------------------------------------------*/
#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 // SINGLETON_H

ConfigUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 文件名: ConfigUtil.h
#ifndef CONFIGUTIL_H
#define CONFIGUTIL_H

#include "Singleton.h" // [1]
#include <QString>

class ConfigUtil {
SINGLETON(ConfigUtil) // [2]

public:
QString getDatabaseName() const;
};

#endif // CONFIGUTIL_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 文件名: ConfigUtil.cpp
#include "ConfigUtil.h"
#include <QDebug>

// [3]
ConfigUtil::ConfigUtil() {
qDebug() << "ConfigUtil()";
}

// [4]
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()

通过上面对代码的优化,使用模版和宏,实现了大量代码的复用,只需要简单的几条语句,就能实现一个单例的类,让我们把更多的精力放在类的业务逻辑上,而不是浪费在单例实现的那些模版代码上。