c++中單例模式使用及說明(局部靜態(tài)變量)
單例模式的作用
單例模式的核心在于確保一個類只有一個實例,并為整個系統(tǒng)提供統(tǒng)一的訪問入口,從而實現(xiàn)資源與邏輯的精簡。
它通過私有化構(gòu)造函數(shù)來禁止外部隨意創(chuàng)建對象,強制所有代碼通過同一個靜態(tài)方法獲取唯一實例。
這樣做既避免了重復(fù)創(chuàng)建重量級對象(如配置管理器、數(shù)據(jù)庫連接池)的資源浪費,也簡化了對象在系統(tǒng)各處的傳遞與訪問——你不需要在多個模塊間手動傳遞同一個對象,只需通過全局訪問點直接獲取即可。
這種設(shè)計將對象的生命周期與訪問方式標(biāo)準(zhǔn)化,讓代碼更聚焦于業(yè)務(wù)邏輯而非對象管理。但需警惕,過度使用單例會引入全局狀態(tài)隱式耦合,增加測試復(fù)雜度,因此應(yīng)嚴(yán)格限定于真正需要“唯一性”的場景。
總結(jié):
- 單例模式通過控制實例數(shù)量和提供統(tǒng)一訪問點,實現(xiàn)資源管理的精簡與代碼結(jié)構(gòu)的簡化。
- 但需注意多線程安全、單元測試難度等潛在問題,避免濫用。
單例模式(局部靜態(tài)變量模式)
//靜態(tài)局部變量方式實現(xiàn)單例模式
#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;
}
};
單例模式的應(yīng)用(局部靜態(tài)變量)
#include <iostream>
#include <string>
#include <unordered_map>
/**
* 配置管理器單例類
* 在大型項目中,通常需要一個全局唯一的配置中心來管理各種服務(wù)配置項
* 如數(shù)據(jù)庫連接信息、API密鑰、服務(wù)器端口等
*/
class ConfigManager {
private:
// 私有構(gòu)造函數(shù),防止外部直接創(chuàng)建實例
ConfigManager() {
// 在構(gòu)造函數(shù)中加載默認(rèn)配置
loadDefaultConfig();
std::cout << "ConfigManager 初始化完成,加載默認(rèn)配置" << std::endl;
}
// 刪除拷貝構(gòu)造函數(shù)和賦值操作符,確保單例的唯一性
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
// 加載默認(rèn)配置的方法
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:
/**
* 獲取單例實例的靜態(tài)方法
* C++11 標(biāo)準(zhǔn)保證 static 局部變量的初始化是線程安全的
*/
static ConfigManager& getInstance() {
static ConfigManager instance; // 靜態(tài)局部變量,延遲初始化
return instance;
}
/**
* 獲取配置值
* @param key 配置項鍵名
* @return 配置項對應(yīng)的值,如果不存在則返回空字符串
*/
std::string getConfig(const std::string& key) const {
auto it = configMap.find(key);
//std::map<KeyType, ValueType>::iterator it = configMap.find(key);//傳統(tǒng)寫法
if (it != configMap.end()) {
return it->second;
}
std::cout << "警告: 未找到配置項 '" << key << "'" << std::endl;
return "";
}
/**
* 設(shè)置配置值
* 在實際項目中,這個方法可能用于動態(tài)更新配置
* @param key 配置項鍵名
* @param value 配置項值
*/
void setConfig(const std::string& key, const std::string& value) {
configMap[key] = value;
std::cout << "配置項 '" << key << "' 更新為: " << value << std::endl;
}
/**
* 打印所有配置項(用于調(diào)試)
*/
void printAllConfigs() const {
std::cout << "\n=== 當(dāng)前所有配置 ===" << std::endl;
for (const auto& pair : configMap) {
std::cout << pair.first << " = " << pair.second << std::endl;
}
std::cout << "==================\n" << std::endl;
}
};
/**
* 模擬數(shù)據(jù)庫連接類
* 使用配置管理器獲取數(shù)據(jù)庫連接參數(shù)
*/
class DatabaseConnection {
public:
DatabaseConnection() {
// 從配置管理器獲取數(shù)據(jù)庫連接參數(shù)
auto& config = ConfigManager::getInstance();
host = config.getConfig("database_host");
port = config.getConfig("database_port");
std::cout << "正在連接數(shù)據(jù)庫: " << host << ":" << port << std::endl;
}
private:
std::string host;
std::string port;
};
/**
* 模擬 Redis 連接類
* 同樣使用配置管理器獲取 Redis 連接參數(shù)
*/
class RedisConnection {
public:
RedisConnection() {
// 從配置管理器獲取 Redis 連接參數(shù)
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: 數(shù)據(jù)庫連接器獲取配置
std::cout << "\n--- 初始化數(shù)據(jù)庫連接 ---" << 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: 動態(tài)修改配置
std::cout << "\n--- 動態(tài)修改配置 ---" << std::endl;
auto& config = ConfigManager::getInstance();
config.setConfig("database_host", "prod-database.company.com");
config.setConfig("api_timeout", "10000");
// 驗證配置是否更新
std::cout << "更新后的數(shù)據(jù)庫主機: " << 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;
}
運行結(jié)果

總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

