23种设计模式 - 单例模式(Singleton)

单例模式(Singleton)------ 全局就我一个,多了没有,爱用不用

大白话解释

想象一个公司只有一台打印机。不管谁来打印,用的都是同一台机器。如果每次有人要打印就新买一台,那公司得破产。

单例模式就是:整个程序运行期间,某个类只能有一个实例,所有人都共用这一个。

常见场景:

  • 配置文件管理器(配置只需加载一次)
  • 日志系统(全局写同一个日志)
  • 数据库连接池(连接资源宝贵)
  • 窗口管理器(只有一个主窗口)

核心思路

  1. 把构造函数藏起来 (设为 private),外面没法 new 出来
  2. 自己内部保存唯一实例
  3. 提供一个全局访问点(静态方法)

C++ 代码示例

版本一:懒汉式(用到的时候才创建)

cpp 复制代码
#include <iostream>
#include <string>

class ConfigManager {
private:
    // 私有构造函数,外部无法直接 new
    ConfigManager() {
        std::cout << "配置管理器初始化完成!\n";
        dbHost = "localhost";
        dbPort = 3306;
    }

    // 禁止拷贝和赋值(C++11 写法)
    ConfigManager(const ConfigManager &) = delete;
    ConfigManager &operator=(const ConfigManager &) = delete;

    std::string dbHost;
    int dbPort;

public:
    // 全局访问点:第一次调用时创建实例
    static ConfigManager &instance() {
        static ConfigManager instance; // C++11 保证线程安全
        return instance;
    }

    std::string getDbHost() const { return dbHost; }
    int getDbPort() const { return dbPort; }

    void setDbHost(const std::string& host) { dbHost = host; }
};

int main() {
    // 获取单例
    ConfigManager &config1 = ConfigManager::instance();
    ConfigManager &config2 = ConfigManager::instance();

    // 验证是同一个对象
    std::cout << "是同一个对象吗?" << (&config1 == &config2 ? "是" : "否") << "\n";

    // 通过 config1 修改
    config1.setDbHost("192.168.0.100");

    // config2 也能看到修改(因为本来就是同一个)
    std::cout << "config2 的数据库地址:" << config2.getDbHost() << "\n";

    return 0;
}

输出:

复制代码
配置管理器初始化完成!
是同一个对象吗?是
config2 的数据库地址:192.168.0.100

版本二:线程安全的指针版(多线程环境)

cpp 复制代码
#include <iostream>
#include <mutex>

class Logger {
private:
    static Logger *instance;
    static std::mutex mtx;

    Logger() {
        std::cout << "日志系统启动\n";
    }

public:
    static Logger *instance() {
        if (instance == nullptr) {           // 第一次检查(提高效率)
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {       // 第二次检查(保证线程安全)
                instance = new Logger();
            }
        }
        return instance;
    }

    void log(const std::string &msg) {
        std::cout << "[LOG] " << msg << "\n";
    }
};

// 静态成员初始化
Logger *Logger::instance = nullptr;
std::mutex Logger::mtx;

int main() {
    Logger::instance()->log("程序启动");
    Logger::instance()->log("用户登录成功");
    return 0;
}

优缺点

说明
✅ 优点 节约资源,避免重复创建
✅ 优点 全局共享资源,防止冲突
✅ 优点 控制访问,全局只有一个入口
❌ 缺点 没有接口,没有继承,很难扩展新功能
❌ 缺点 单元测试困难(全局状态难以隔离)
❌ 缺点 生命周期管理不灵活,一旦创建,无法手动销毁、重启
❌ 缺点 到处都能直接调用,代码可读性变差,难以清理依赖
相关推荐
Java面试题总结2 小时前
双重检验锁的单例模式在高并发下的可见性问题
单例模式
珊瑚里的鱼3 天前
手撕单例模式中的饿汉模式和懒汉模式,懒汉模式还要再多加一个C++11版本的
开发语言·c++·单例模式
韩曙亮3 天前
【Flutter】Dart 单例 ( 单例模式核心规则 | 饿汉式单例 | 懒汉式单例 | 极简空安全 懒汉式单例 | 工厂构造函数单例 )
flutter·单例模式·dart·饿汉式单例·懒汉式单例·空安全·空赋值
wunaiqiezixin5 天前
如何在C++中实现一个单例模式?
c++·单例模式
basketball6165 天前
设计模式入门:1. 单例模式详解 C++实现
c++·单例模式·设计模式
bugcome_com5 天前
阿里云OSS工具类完整设计与实现:基于.NET的静态单例模式实践
阿里云·单例模式·.net·oss
JAVA9655 天前
JAVA面试-并发篇 03-使用synchronized doublecheck实现单例有什么坑
java·单例模式·面试
HEADKON9 天前
司拉德帕失代偿期肝硬化及胆道梗阻患者禁止使用,肝酶升高需暂停药物
单例模式
IT空门:门主11 天前
Java 单例模式详解:7 种实现方式 + volatile 原理 + 反射与序列化问题
java·开发语言·单例模式