设计模式 | 单例模式 | 懒汉&饿汉

什么是单例模式呢?就是只允许有一个实例对象

所以单例模式会有以下特征:

必须是通过静态成员函数去创建那唯一的实例对象,而且这个实例也必须是静态的

还有构造函数必须私有,拷贝构造、赋值重载全部禁用

由单例模式都有哪些场景?

线程池、资源分配、日志记录

数据库连接池: 在多线程环境中,数据库连接的创建和销毁是开销较大的操作,使用单例模式可以确保整个应用程序只有一个数据库连接池实例,避免了资源的浪费。

日志记录器: 在应用程序中,通常只需要一个日志记录器来记录系统的运行状态和错误信息,使用单例模式可以确保所有组件共享同一个日志记录器,避免了多个实例产生的混乱。

配置管理器: 应用程序的配置信息通常是全局共享的,使用单例模式可以确保整个应用程序只有一个配置管理器实例,方便统一管理和修改配置信息。

线程池: 在多线程环境中,线程池可以提高任务处理的效率,使用单例模式可以确保整个应用程序只有一个线程池实例,方便任务的提交和管理。

缓存管理器: 缓存是提高应用程序性能的重要手段之一,使用单例模式可以确保整个应用程序只有一个缓存管理器实例,避免了多个缓存管理器实例之间的数据不一致。

然后又有饿汉模式跟懒汉模式

什么是饿汉模式

在程序启动时即创建单例对象,并且在整个生命周期中保持不变。

在类加载时就创建单例对象,并在程序运行期间一直存在,无论是否需要使用该对象。

线程安全,因为对象在类加载时就已经创建,不会出现多线程竞争的情况。

实现简单,适用于单例对象较小且在应用程序中经常被使用的情况。

cpp 复制代码
#include <iostream>

class Singleton {
public:
    // 获取单例实例的静态方法						#3 获取类的唯一实例对象的接口方法
    static Singleton& getInstance() {
        // 使用静态局部变量保证线程安全的懒汉模式	#2定义唯一的类的实例对象
        static Singleton instance;
        return instance;
    }

    // 将拷贝构造函数删除,防止通过拷贝构造函数创建实例
    Singleton(const Singleton&) = delete;

    // 将赋值操作符删除,防止通过赋值操作符创建实例
    Singleton& operator=(const Singleton&) = delete;

    // 提供一些公共方法
    void doSomething() {
        std::cout << "Singleton is doing something." << std::endl;
    }

private:
    // 将构造函数私有化,防止外部直接创建实例		#1 构造函数私有化
    Singleton() {
        // 可以在构造函数中进行一些初始化操作
    }

    // 将析构函数私有化,防止外部删除实例
    ~Singleton() {
        // 可以在析构函数中进行一些清理工作
    }
};

int main() {

    // 不能通过构造函数自己创建对象,只能通过类的静态方法来获取这个类的唯一对象
    // 通过禁用拷贝构造、赋值重载 都要禁用 
    // 获取单例实例
    Singleton& instance1 = Singleton::getInstance();
    Singleton& instance2 = Singleton::getInstance();
    Singleton& instance3 = Singleton::getInstance();

    // 调用单例实例的方法
    instance1.doSomething();

    return 0;
}

懒汉模式

在需要时才创建单例对象,而不是在程序启动时就创建。

第一次调用 getInstance() 方法时才会创建单例对象,延迟了单例对象的实例化。

线程不安全,如果多个线程同时调用 getInstance() 方法,并且单例对象尚未创建,则可能导致创建多个实例的情况。

需要使用双重检查锁定(Double-Checked Locking)或者使用静态内部类来保证线程安全。

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

//		volate 关键字 当某一个线程给 instace 赋值 其他线程就能立马知道instace 被赋值
//		线程  已经不对 共享变量  instace  缓存
class Singleton{
    public:
        // 是否是可重入函数呢?  		临界区代码段  保证操作的原子性  锁 + 双重判断
        static Singleton* getInstance(){
            
            if(instance == nullptr){			// 1重

                std::lock_guard<std::mutex> lock(mutex_);

                if(instance == nullptr){		// 2重
                    
                    instance = new Singleton();
                }
                
            }
            return instance;
        }
    private:
        static Singleton* volate instance;		// #2 定义一个唯一的类的实例对象
        // #1 构造函数私有化
        Singleton(){}
        Singleton(const Singleton&) = delete;
        Singleton& operator = (const Singleton&) = delete;
        // 静态成员变量用于保证线程安全
        static std::mutex mutex_;
};
Singleton*volate  Singleton::instance = nullptr;
std::mutex Singleton::mutex_;

int main(){
    Singleton* p1 = Singleton::getInstance();		// instance 为nullptr 创建 实例对象
    Singleton* p2 = Singleton::getInstance();		// instance 不为空  直接返回 实例
}
相关推荐
触底反弹5 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
张小姐的猫1 天前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式