第一章:单例模式 - 武林中的孤高剑客
故事延续:孤高剑客的独门绝技
在架构老人宣布华山论剑开始后,Singleton(单例模式)率先踏出一步,他那如雪的白衣在圣殿的流光中显得格外耀眼。周围的高手们都不禁为他那"唯我独尊"的气场所震慑。
"既然盟主有令,那就由在下先来展示独门绝技吧。" Singleton声音清冷,却带着不容置疑的权威,"在软件江湖中,有些存在天生就该独一无二------配置管理器、线程池、日志系统、数据库连接池...这些核心资源若被随意创建,必将导致系统混乱!"
单例模式的武学精要
核心心法
Singleton缓缓抬起右手,掌心浮现出一团旋转的二进制代码:"我的武学核心只有八字真言------确保一类仅存一实例。通过私有化构造函数,让外界无法随意创建,再提供统一的访问入口,让天下英雄都能找到这唯一的我。"
C++ 代码实战
cpp
#include <iostream>
#include <mutex>
#include <memory>
// 单例模式 - 懒汉式(线程安全版本)
class Singleton {
private:
// 私有的静态实例指针
static Singleton* instance;
static std::mutex mutex_;
// 私有构造函数,防止外部实例化
Singleton() {
std::cout << "Singleton 实例被创建!" << std::endl;
}
// 私有拷贝构造和赋值操作,防止复制
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
// 公有静态方法,提供全局访问点
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
// 业务方法示例
void doSomething() {
std::cout << "Singleton 正在处理业务..." << std::endl;
}
// 释放资源
static void destroyInstance() {
std::lock_guard<std::mutex> lock(mutex_);
if (instance != nullptr) {
delete instance;
instance = nullptr;
std::cout << "Singleton 实例已被销毁!" << std::endl;
}
}
};
// 静态成员初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;
// 现代C++推荐写法 - 使用局部静态变量(C++11线程安全)
class ModernSingleton {
private:
ModernSingleton() {
std::cout << "ModernSingleton 实例被创建!" << std::endl;
}
public:
static ModernSingleton& getInstance() {
static ModernSingleton instance; // C++11保证线程安全
return instance;
}
void doSomething() {
std::cout << "ModernSingleton 正在处理业务..." << std::endl;
}
// 删除拷贝构造和赋值操作
ModernSingleton(const ModernSingleton&) = delete;
ModernSingleton& operator=(const ModernSingleton&) = delete;
};
// 模板单例 - 让单例模式更通用
template<typename T>
class TemplateSingleton {
protected:
TemplateSingleton() = default;
virtual ~TemplateSingleton() = default;
public:
static T& getInstance() {
static T instance;
return instance;
}
TemplateSingleton(const TemplateSingleton&) = delete;
TemplateSingleton& operator=(const TemplateSingleton&) = delete;
};
// 具体业务类使用模板单例
class ConfigurationManager : public TemplateSingleton<ConfigurationManager> {
friend class TemplateSingleton<ConfigurationManager>;
private:
std::string configData;
ConfigurationManager() {
configData = "默认配置数据";
std::cout << "配置管理器初始化完成!" << std::endl;
}
public:
void loadConfig(const std::string& data) {
configData = data;
std::cout << "配置已加载: " << configData << std::endl;
}
std::string getConfig() const {
return configData;
}
};
UML 武功秘籍图
Singleton -static Singleton* instance -static mutex mutex_ -Singleton() +static Singleton* getInstance() +doSomething() : void +static destroyInstance() ModernSingleton -ModernSingleton() +static getInstance() +doSomething() : void TemplateSingleton<T> #TemplateSingleton() +static getInstance() ConfigurationManager -string configData -ConfigurationManager() +loadConfig(string) : void +getConfig() : string
实战演练:日志系统的单例实现
cpp
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>
// 实战案例:日志系统单例
class Logger : public TemplateSingleton<Logger> {
friend class TemplateSingleton<Logger>;
private:
std::ofstream logFile;
bool enabled;
Logger() : enabled(true) {
logFile.open("application.log", std::ios::app);
if (!logFile.is_open()) {
std::cerr << "无法打开日志文件!" << std::endl;
enabled = false;
}
}
~Logger() {
if (logFile.is_open()) {
logFile.close();
}
}
std::string getCurrentTime() {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
return ss.str();
}
public:
void log(const std::string& message, const std::string& level = "INFO") {
if (!enabled) return;
std::string logEntry = "[" + getCurrentTime() + "] " +
"[" + level + "] " + message;
std::cout << logEntry << std::endl;
if (logFile.is_open()) {
logFile << logEntry << std::endl;
logFile.flush();
}
}
void error(const std::string& message) {
log(message, "ERROR");
}
void warn(const std::string& message) {
log(message, "WARN");
}
void info(const std::string& message) {
log(message, "INFO");
}
};
// 数据库连接池单例
class DatabaseConnectionPool {
private:
static DatabaseConnectionPool* instance;
static std::mutex mutex_;
int maxConnections;
int currentConnections;
DatabaseConnectionPool() : maxConnections(10), currentConnections(0) {
std::cout << "数据库连接池初始化,最大连接数: " << maxConnections << std::endl;
}
public:
static DatabaseConnectionPool* getInstance() {
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) {
instance = new DatabaseConnectionPool();
}
return instance;
}
bool acquireConnection() {
std::lock_guard<std::mutex> lock(mutex_);
if (currentConnections < maxConnections) {
currentConnections++;
std::cout << "获取数据库连接成功,当前连接数: " << currentConnections << std::endl;
return true;
}
std::cout << "获取数据库连接失败,连接池已满!" << std::endl;
return false;
}
void releaseConnection() {
std::lock_guard<std::mutex> lock(mutex_);
if (currentConnections > 0) {
currentConnections--;
std::cout << "释放数据库连接,当前连接数: " << currentConnections << std::endl;
}
}
static void destroyInstance() {
std::lock_guard<std::mutex> lock(mutex_);
if (instance != nullptr) {
delete instance;
instance = nullptr;
}
}
};
DatabaseConnectionPool* DatabaseConnectionPool::instance = nullptr;
std::mutex DatabaseConnectionPool::mutex_;
单例模式的招式解析
招式一:懒汉式(Lazy Initialization)
cpp
// 特点:需要时才创建实例,节省资源
// 缺点:需要处理多线程安全问题
招式二:饿汉式(Eager Initialization)
cpp
class EagerSingleton {
private:
static EagerSingleton instance; // 类加载时就初始化
EagerSingleton() = default;
public:
static EagerSingleton& getInstance() {
return instance; // 直接返回已创建的实例
}
};
// 静态成员定义
EagerSingleton EagerSingleton::instance;
招式三:Meyer's Singleton(推荐)
cpp
// 利用C++11的局部静态变量线程安全特性
// 简洁、安全、自动销毁
完整测试代码
cpp
// 测试单例模式的各种实现
void testSingletonPattern() {
std::cout << "=== 单例模式测试开始 ===" << std::endl;
// 测试传统单例
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
std::cout << "传统单例地址比较: " << (s1 == s2 ? "相同" : "不同") << std::endl;
// 测试现代单例
ModernSingleton& ms1 = ModernSingleton::getInstance();
ModernSingleton& ms2 = ModernSingleton::getInstance();
std::cout << "现代单例地址比较: " << (&ms1 == &ms2 ? "相同" : "不同") << std::endl;
// 测试模板单例 - 配置管理器
ConfigurationManager& config1 = ConfigurationManager::getInstance();
ConfigurationManager& config2 = ConfigurationManager::getInstance();
config1.loadConfig("服务器配置数据");
std::cout << "配置数据: " << config2.getConfig() << std::endl;
std::cout << "配置管理器地址比较: " << (&config1 == &config2 ? "相同" : "不同") << std::endl;
// 测试日志系统
Logger::getInstance().info("应用程序启动");
Logger::getInstance().warn("内存使用率较高");
Logger::getInstance().error("数据库连接失败");
// 测试数据库连接池
DatabaseConnectionPool* pool = DatabaseConnectionPool::getInstance();
pool->acquireConnection();
pool->acquireConnection();
pool->releaseConnection();
std::cout << "=== 单例模式测试结束 ===" << std::endl;
}
int main() {
testSingletonPattern();
return 0;
}
单例模式的武学心得
适用场景
- 资源共享:数据库连接池、线程池
- 配置管理:应用程序配置信息
- 日志系统:统一的日志记录
- 设备管理器:打印机、文件系统等
优点
- 严格控制实例数量:确保全局唯一性
- 全局访问点:方便其他对象访问
- 延迟初始化:需要时才创建,节省资源
缺点
- 违反单一职责原则:同时承担创建和业务逻辑
- 测试困难:难以模拟和测试
- 隐藏依赖关系:全局状态可能带来意想不到的副作用
武林高手的点评
Factory Method 抚掌笑道:"Singleton 兄果然了得!你这'唯一存在'的武学理念,在需要严格控制实例数量的场景下确实无人能及。不过..." 他话锋一转,"过度使用可能导致代码耦合度增加,还需谨慎为之啊!"
Singleton 微微颔首:"道兄所言极是。我这武学虽强,却不可滥用。只有在真正需要全局唯一性的场景下,才该请我出手。"
下章预告
在Singleton展示完他那孤高的剑法后,Factory Method 缓步走出,他腰间工具碰撞的清脆声响吸引了所有人的注意。
"Singleton 兄的'唯一之道'确实精妙,但软件江湖中,更多时候我们需要的是'灵活创造'的能力。" Factory Method 微笑着说道,"下一章,我将为大家展示如何通过'工厂方法'来解耦对象的创建与使用,让我们的系统更加灵活、可扩展!"
架构老人满意地点头:"善!创造之道,变化万千。下一章,就请 Factory Method 展示他的创造艺术!"
欲知 Factory Method 如何通过工厂方法模式实现对象的灵活创建,且听下回分解!