设计模式(design patterns)是软件体系结构中一个比较深入的话题。其中,单件(singleton)模式是其中最简单的一种,它描述了下述应用场景其及解决方案:在程序中,有些类型我们最多只需要一个对象,比如数据库连接、错误日志记录器等等。单件模式试图通过特殊的类设计确保该类型最多只能被实例化一次。

版权声明

本文可以在互联网上自由转载,但必须:注明出处(作者:海洋饼干叔叔)并包含指向本页面的链接。

本文不可以以纸质出版为目的进行改编、摘抄。

  下述C++程序演示了一个名为Daemon的单件类,它是通过静态成员函数来实现的。

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
//Project - Singleton
#include <iostream>
using namespace std;

class Daemon {
private:
static Daemon* instance;
Daemon(){} //将构造函数私有
Daemon(const Daemon&){} //将拷贝构造函数私有
public:
static Daemon* Instance(){
if (instance==nullptr)
instance = new Daemon();
return instance;
}
};

Daemon* Daemon::instance {nullptr};

int main() {
//Daemon d; //错误:私有的构造函数不能执行
//Daemon* d = new Daemon();

Daemon* d1 = Daemon::Instance();
//借助于d1指针使用唯一的Daemon对象...
Daemon* d2 = Daemon::Instance();
//借助于d2指针使用唯一的Daemon对象...

cout << "d1 = " << d1 << ", d2 = " << d2 << endl;

delete Daemon::Instance(); //释放唯一的Daemon对象
return 0;
}

上述程序的执行结果为:

1
d1 = 0xe517b0, d2 = 0xe517b0

说明:在读者的计算机上,执行结果中的地址很可能与本书不同。

🚩第6 ~ 9行:Daemon类型的构造函数被私有,这意味着类型的使用者无法直接定义Daemon对象。

  Daemon类型的拷贝构造函数(copy constructor)▲也被私有,这意味着类型的使用者无法通过对象的拷贝赋值来创建Daemon对象。

🚩第10 ~ 15行:公有的静态成员函数Instance()用于返回唯一的Daemon对象的指针。该指针保存在静态数据成员instance里,当instance为空时,说明当前程序中不存在Daemon对象,第13行通过new操作符新建一个Daemon对象并将其地址赋值给instance。由于Instance()是Daemon类的成员函数,所以此处对Daemon的构造函数的调用是合法的。

🚩第21 ~ 22行:任何常规的对象创建方法都需要调用Daemon的构造函数,但其构造函数是私有的。

🚩第24 ~ 27行:类的使用者仅被允许通过Instance()获取唯一的Daemon对象的指针,然后再借助于获取的指针来使用该对象。

🚩第29行:执行结果证实,每次调用Instance()函数所获取的指针,都是同一个值。它们都指向那个“唯一”的Daemon对象。

🚩第31行:唯一的Daemon对象必须被释放,否则会造成内存泄漏。

  借助于单件模式,在类的设计阶段就保证了该类最多只能被实例化一次,以避免类的使用者不小心犯错(意外创建多个类对象)。