C++ 中的单例模式
Singleton Pattern 是一种设计模式,它允许创建一个 class 的唯一对象。它不允许多次调用时创建多个实例,而是确保 class 只创建一个实例,并提供一个全局访问点,以便在代码的任何地方都能访问它。
当系统中需要恰好一个对象来协调各项操作时,singleton pattern 就很有用。例如,想象你在办公室需要使用打印机。与其为每个员工配备一台打印机,不如使用一台所有员工共享的打印机。这样可以确保同一时间只有一个人使用打印机,同时还能节省资源。
Singleton Pattern 的关键点
Singleton Pattern 的关键点如下 −
- 它将 class 的实例化限制为单个实例。
- 它为该实例提供全局访问点。
- 它常用于管理共享资源,如数据库连接、配置设置、日志记录等。
- 它可以使用 lazy initialization 实现,即实例仅在首次需要时才创建。
C++ 中 Singleton Pattern 的实现
C++ 中实现 Singleton Pattern 有多种方式。一些重要且常用的实现包括 −
- Lazy Initialization Singleton
- Eager Initialization Singleton (Hungry Singleton)
- Mayers' Singleton
大多数情况下使用 lazy initialization singleton,因为它更高效且节省内存。不过,eager initialization singleton 更简单且是 thread-safe 的。Mayers' singleton 实现是 C++ 中创建 singleton class 的优秀现代方法。
Lazy Initialization Singleton
在这种方法中,class 的实例仅在首次需要时才创建。这有助于只创建 class 的一个实例,同时节省内存。
C++ 中实现 Singleton Pattern 的步骤
C++ 中实现 Singleton Pattern 的步骤如下 −
- 将 class 的 constructor 设为 private,以防止从 class 外部实例化。
- 然后,创建一个 static 变量来保存 class 的单个实例。
- 创建一个 static 方法返回 class 的实例。该方法检查实例是否已创建,如果未创建则创建一个并返回;否则,直接返回现有实例。
C++ 中 Singleton Pattern 示例
在下面的示例中,我们有一个 Logger class 实现了 singleton pattern。getInstance() 方法返回 Logger class 的单个实例。log() 方法用于记录消息。
让我们使用 Singleton Pattern 在 C++ 中实现一个简单的 Logger class。
#include <iostream>
#include <string>
using namespace std;
// Logger 的 Lazy Initialization Singleton
class Logger {
private:
static Logger* instance;
Logger() {}
public:
static Logger* getInstance() {
if (instance == nullptr) {
instance = new Logger();
}
return instance;
}
void log(string message) {
cout << "Log: " << message << endl;
}
};
// 初始化静态成员
Logger* Logger::instance = nullptr;
// 主函数
int main() {
Logger* logger = Logger::getInstance();
logger->log("This is a log message.");
Logger* l1 = Logger::getInstance();
l1->log("This is another log message.");
return 0;
}
以上程序的输出如下 −
Log: This is a log message. Log: This is another log message.
急切初始化单例(饥饿单例)实现
在这种方法中,我们在类加载时创建类的实例。这种方法更简单,并且是线程安全的。然而,这种方法的缺点是即使实例未被使用,也会创建实例,这可能导致资源浪费。因此,如果您确定实例会被使用,这种方法是一个不错的选择。
C++ 中急切初始化单例模式的示例
让我们使用 C++ 中的急切初始化单例模式实现一个简单的 Logger 类。
#include <iostream>
#include <string>
using namespace std;
// Logger 的急切初始化单例
class Logger {
private:
static Logger* instance;
Logger() {}
public:
static Logger* getInstance() {
return instance;
}
void log(string message) {
cout << "Log: " << message << endl;
}
};
// 在类加载时初始化实例
Logger* Logger::instance = new Logger();
// 主函数
int main() {
Logger* logger = Logger::getInstance();
logger->log("This is a log message.");
Logger* l1 = Logger::getInstance();
l1->log("This is another log message.");
return 0;
}
以上程序的输出如下 −
Log: This is a log message. Log: This is another log message.
Meyers' 单例实现
Meyers' 单例实现是 C++ 中创建单例类的一种非常好的现代方法。这种方法在 getInstance() 方法中使用静态局部变量来保存类的单个实例。实例在方法第一次被调用时创建,并在程序退出时自动销毁。这种方法是线程安全的,并且确保只创建一个类的实例。
C++ 中 Meyers' 单例模式的示例
让我们使用 C++ 中的 Meyers' 单例模式实现一个简单的 Logger 类。
#include <iostream>
#include <string>
using namespace std;
// Logger 的 Meyers' 单例
class Logger {
private:
Logger() {}
public:
static Logger& getInstance() {
static Logger instance;
return instance;
}
void log(string message) {
cout << "Log: " << message << endl;
}
};
// 主函数
int main() {
Logger& logger = Logger::getInstance();
logger.log("This is a log message.");
Logger& l1 = Logger::getInstance();
l1.log("This is another log message.");
return 0;
}
以上程序的输出如下 −
Log: This is a log message. Log: This is another log message.
单例模式在实际中的使用场景
以下是单例模式的一些实际使用场景 −
- Logger 类 − 如示例所示,Logger 类使用单例模式,因此可以在任何地方访问,但整个应用程序只创建一个实例。
- 配置类 − 配置类可以实现为单例,以确保整个应用程序中只有一个配置设置的实例。
- 数据库连接类 − 另一个使用场景是实现数据库连接类,这样就不需要创建多个数据库连接。
- 打印假脱机 − 打印假脱机可以实现为单例,以集中管理打印作业。因此,整个系统只有一个打印假脱机的实例,而不是为系统上的每个应用程序创建多个实例。
结论
在本章中,我们详细介绍了 C++ 中的 Singleton Pattern。我们解释了如何实现它,并提供了一个使用 singleton pattern 的 Logger class 示例。Singleton pattern 是一种有用的设计模式,它有助于管理共享资源,并确保 class 只创建一个实例。