单例模式的作用:
单例模式的核心在于确保一个类只有一个实例,并为整个系统提供统一的访问入口,从而实现资源与逻辑的精简。它通过私有化构造函数来禁止外部随意创建对象,强制所有代码通过同一个静态方法获取唯一实例。这样做既避免了重复创建重量级对象(如配置管理器、数据库连接池)的资源浪费,也简化了对象在系统各处的传递与访问------你不需要在多个模块间手动传递同一个对象,只需通过全局访问点直接获取即可。这种设计将对象的生命周期与访问方式标准化,让代码更聚焦于业务逻辑而非对象管理。但需警惕,过度使用单例会引入全局状态隐式耦合,增加测试复杂度,因此应严格限定于真正需要"唯一性"的场景。
总结
单例模式通过控制实例数量和提供统一访问点,实现资源管理的精简与代码结构的简化。但需注意多线程安全、单元测试难度等潜在问题,避免滥用。
单例模式(局部静态变量模式):
cpp
//静态局部变量方式实现单例模式
#include<iostream>
using namespace std;
class S {
private:
S() {}
S(const S&) = delete;
S& operator=(const S&) = delete;
public:
static S& getS() {
static S s;
return s;
}
};
单例模式的应用(局部静态变量):
cpp
#include <iostream>
#include <string>
#include <unordered_map>
/**
* 配置管理器单例类
* 在大型项目中,通常需要一个全局唯一的配置中心来管理各种服务配置项
* 如数据库连接信息、API密钥、服务器端口等
*/
class ConfigManager {
private:
// 私有构造函数,防止外部直接创建实例
ConfigManager() {
// 在构造函数中加载默认配置
loadDefaultConfig();
std::cout << "ConfigManager 初始化完成,加载默认配置" << std::endl;
}
// 删除拷贝构造函数和赋值操作符,确保单例的唯一性
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
// 加载默认配置的方法
void loadDefaultConfig() {
configMap["database_host"] = "localhost";
configMap["database_port"] = "3306";
configMap["redis_host"] = "localhost";
configMap["redis_port"] = "6379";
configMap["api_timeout"] = "5000"; // 毫秒
configMap["max_connections"] = "100";
}
// 存储配置项的哈希表
std::unordered_map<std::string, std::string> configMap;
public:
/**
* 获取单例实例的静态方法
* C++11 标准保证 static 局部变量的初始化是线程安全的
*/
static ConfigManager& getInstance() {
static ConfigManager instance; // 静态局部变量,延迟初始化
return instance;
}
/**
* 获取配置值
* @param key 配置项键名
* @return 配置项对应的值,如果不存在则返回空字符串
*/
std::string getConfig(const std::string& key) const {
auto it = configMap.find(key);
//std::map<KeyType, ValueType>::iterator it = configMap.find(key);//传统写法
if (it != configMap.end()) {
return it->second;
}
std::cout << "警告: 未找到配置项 '" << key << "'" << std::endl;
return "";
}
/**
* 设置配置值
* 在实际项目中,这个方法可能用于动态更新配置
* @param key 配置项键名
* @param value 配置项值
*/
void setConfig(const std::string& key, const std::string& value) {
configMap[key] = value;
std::cout << "配置项 '" << key << "' 更新为: " << value << std::endl;
}
/**
* 打印所有配置项(用于调试)
*/
void printAllConfigs() const {
std::cout << "\n=== 当前所有配置 ===" << std::endl;
for (const auto& pair : configMap) {
std::cout << pair.first << " = " << pair.second << std::endl;
}
std::cout << "==================\n" << std::endl;
}
};
/**
* 模拟数据库连接类
* 使用配置管理器获取数据库连接参数
*/
class DatabaseConnection {
public:
DatabaseConnection() {
// 从配置管理器获取数据库连接参数
auto& config = ConfigManager::getInstance();
host = config.getConfig("database_host");
port = config.getConfig("database_port");
std::cout << "正在连接数据库: " << host << ":" << port << std::endl;
}
private:
std::string host;
std::string port;
};
/**
* 模拟 Redis 连接类
* 同样使用配置管理器获取 Redis 连接参数
*/
class RedisConnection {
public:
RedisConnection() {
// 从配置管理器获取 Redis 连接参数
auto& config = ConfigManager::getInstance();
host = config.getConfig("redis_host");
port = config.getConfig("redis_port");
std::cout << "正在连接 Redis: " << host << ":" << port << std::endl;
}
private:
std::string host;
std::string port;
};
int main() {
std::cout << "=== 大厂项目配置管理器演示 ===" << std::endl;
// 场景1: 数据库连接器获取配置
std::cout << "\n--- 初始化数据库连接 ---" << std::endl;
DatabaseConnection dbConn;
// 场景2: Redis连接器获取配置
std::cout << "\n--- 初始化Redis连接 ---" << std::endl;
RedisConnection redisConn;
// 场景3: 验证单例的唯一性
std::cout << "\n--- 验证单例模式 ---" << std::endl;
auto& config1 = ConfigManager::getInstance();
auto& config2 = ConfigManager::getInstance();
if (&config1 == &config2) {
std::cout << "验证成功: 两次获取的实例是同一个对象" << std::endl;
}
else {
std::cout << "验证失败: 获取到了不同的实例" << std::endl;
}
// 场景4: 动态修改配置
std::cout << "\n--- 动态修改配置 ---" << std::endl;
auto& config = ConfigManager::getInstance();
config.setConfig("database_host", "prod-database.company.com");
config.setConfig("api_timeout", "10000");
// 验证配置是否更新
std::cout << "更新后的数据库主机: " << config.getConfig("database_host") << std::endl;
std::cout << "更新后的API超时时间: " << config.getConfig("api_timeout") << "ms" << std::endl;
// 场景5: 打印所有配置
config.printAllConfigs();
// 场景6: 模拟新连接使用更新后的配置
std::cout << "\n--- 新连接使用更新后的配置 ---" << std::endl;
DatabaseConnection newDbConn; // 这个连接会使用更新后的主机地址
return 0;
}
运行结果
