单例模式(Singleton Pattern)用于确保一个类只有一个实例,并提供全局访问点。它的主要目的是控制实例的创建,以便于在整个程序中共享相同的实例。
单例模式的特点
1、 唯一实例:确保某个类只有一个实例;
2、 全局访问点:提供一个访问该实例的全局访问点;
实现单例模式的步骤
1、 私有化构造函数:防止外界通过构造函数创建实例;
2、 静态成员变量:用于保存单例实例的指针;
3、 静态公有方法:用于返回单例实例的指针;
单例模式适用于以下场景:
1、 全局配置管理:如读取配置文件后,全局共享配置对象;
2、 日志系统:日志对象在系统中应当是唯一的,避免多实例导致混乱;
3、 资源管理:如线程池、数据库连接池等,确保资源的全局唯一性和统一管理;
4、 缓存:如应用程序级缓存,保证缓存数据的一致性;
常见的实现方式有懒汉模式和饿汉模式。本文将详细介绍这两种模式,并通过类图和实际案例来说明其应用。
懒汉模式(Lazy Initialization)
懒汉模式指的是在需要使用实例时才进行实例化。它的优点是只有在第一次使用时才创建实例,节省资源,但缺点是需要注意线程安全问题。
懒汉模式实现:
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
// 私有化构造函数
Singleton() {
std::cout << "Singleton instance created." << std::endl;
}
public:
// 禁止拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 静态公有方法获取单例实例
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
Singleton* s1 = Singleton::getInstance();
s1->showMessage();
Singleton* s2 = Singleton::getInstance();
s2->showMessage();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
return 0;
}
饿汉模式(Eager Initialization)
饿汉模式指的是在类加载时就进行实例化。它的优点是线程安全,简单,但缺点是无论实例是否会用到,都在程序启动时创建实例,可能浪费资源。
饿汉模式实现:
#include <iostream>
class Singleton {
private:
// 静态实例在类加载时创建
static Singleton* instance;
// 私有化构造函数
Singleton() {
std::cout << "Singleton instance created." << std::endl;
}
public:
// 禁止拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 静态公有方法获取单例实例
static Singleton* getInstance() {
return instance;
}
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 初始化静态成员
Singleton* Singleton::instance = new Singleton();
int main() {
Singleton* s1 = Singleton::getInstance();
s1->showMessage();
Singleton* s2 = Singleton::getInstance();
s2->showMessage();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
return 0;
}
类图对比:
实际案例
日志系统(懒汉模式)
#include <iostream>
#include <fstream>
#include <mutex>
class Logger {
private:
static Logger* instance;
static std::mutex mtx;
std::ofstream logFile;
// 私有化构造函数
Logger() {
logFile.open("log.txt", std::ios::app);
}
public:
// 析构函数
~Logger() {
if (logFile.is_open()) {
logFile.close();
}
}
// 禁止拷贝构造和赋值运算符
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
// 静态公有方法获取单例实例
static Logger* getInstance() {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Logger();
}
return instance;
}
// 日志记录方法
void log(const std::string& message) {
std::lock_guard<std::mutex> lock(mtx);
if (logFile.is_open()) {
logFile << message << std::endl;
}
}
};
// 初始化静态成员
Logger* Logger::instance = nullptr;
std::mutex Logger::mtx;
int main() {
Logger* logger = Logger::getInstance();
logger->log("Application started");
logger->log("An error occurred");
return 0;
}
配置管理器(饿汉模式)
#include <iostream>
#include <string>
class ConfigManager {
private:
// 静态实例指针
static ConfigManager* instance;
// 配置值
std::string configValue;
// 私有化构造函数,防止外部实例化
ConfigManager() {
// 假设读取配置文件
configValue = "Initial Config";
std::cout << "ConfigManager instance created." << std::endl;
}
public:
// 禁止拷贝构造和赋值运算符
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
// 静态公有方法获取单例实例
static ConfigManager* getInstance() {
return instance;
}
// 获取配置值
std::string getConfig() {
return configValue;
}
// 设置配置值
void setConfig(const std::string& value) {
configValue = value;
}
};
// 初始化静态成员
ConfigManager* ConfigManager::instance = new ConfigManager();
int main() {
// 获取单例实例
ConfigManager* config = ConfigManager::getInstance();
// 输出初始配置值
std::cout << "Config: " << config->getConfig() << std::endl;
// 更新配置值
config->setConfig("Updated Config");
// 输出更新后的配置值
std::cout << "Config: " << config->getConfig() << std::endl;
return 0;
}
总结
懒汉模式和饿汉模式各有优缺点,具体选择应根据应用场景和实际需求来决定。在实际开发中,单例模式广泛应用于全局配置管理、日志系统、资源管理等场景,确保全局实例的唯一性和一致性。
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: