第一章:单例模式 - 武林中的孤高剑客
第一章:单例模式 - 武林中的孤高剑客
故事延续:孤高剑客的独门绝技
在架构老人宣布华山论剑开始后,Singleton(单例模式)率先踏出一步,他那如雪的白衣在圣殿的流光中显得格外耀眼。周围的高手们都不禁为他那"唯我独尊"的气场所震慑。
“既然盟主有令,那就由在下先来展示独门绝技吧。” Singleton声音清冷,却带着不容置疑的权威,“在软件江湖中,有些存在天生就该独一无二——配置管理器、线程池、日志系统、数据库连接池…这些核心资源若被随意创建,必将导致系统混乱!”
单例模式的武学精要
核心心法
Singleton缓缓抬起右手,掌心浮现出一团旋转的二进制代码:“我的武学核心只有八字真言——确保一类仅存一实例。通过私有化构造函数,让外界无法随意创建,再提供统一的访问入口,让天下英雄都能找到这唯一的我。”
C++ 代码实战
#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 武功秘籍图
实战演练:日志系统的单例实现
#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)
// 特点:需要时才创建实例,节省资源
// 缺点:需要处理多线程安全问题
招式二:饿汉式(Eager Initialization)
class EagerSingleton {
private:static EagerSingleton instance; // 类加载时就初始化EagerSingleton() = default;public:static EagerSingleton& getInstance() {return instance; // 直接返回已创建的实例}
};// 静态成员定义
EagerSingleton EagerSingleton::instance;
招式三:Meyer’s Singleton(推荐)
// 利用C++11的局部静态变量线程安全特性
// 简洁、安全、自动销毁
完整测试代码
// 测试单例模式的各种实现
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 如何通过工厂方法模式实现对象的灵活创建,且听下回分解!