设计模式-单例模式

目录

一、什么是单例模式?

1.1单例模式的特点:

二、什么时候使用单例模式?

2.1适用场景

2.2实际应用案例

三、单例模式的不同实现方式

[3.1懒汉式(Lazy Initialization,线程不安全)](#3.1懒汉式(Lazy Initialization,线程不安全))

3.2线程安全的懒汉式

[3.3双重检查锁(Double-Checked Locking)](#3.3双重检查锁(Double-Checked Locking))

[3.4饿汉式(Eager Initialization)](#3.4饿汉式(Eager Initialization))

3.5C++11静态局部变量

四、注意事项

4.1线程安全

4.2内存管理

4.3禁止拷贝和赋值

4.4适用性


一、什么是单例模式?

在软件开发中,某些对象只需要一个实例,且该实例应该在整个系统范围内被共享。这种需求催生了 单例模式(Singleton Pattern) 。单例模式是一种 创建型设计模式,它确保一个类在整个应用程序的生命周期中只有一个实例,并提供一个全局访问点。

1.1单例模式的特点:

  • 唯一实例:确保一个类只有一个对象。

  • 全局访问:提供一个公共访问点来获取实例。

  • 延迟实例化(可选):在首次使用时创建实例,避免不必要的资源浪费。

二、什么时候使用单例模式?

2.1适用场景

  • 配置管理:应用程序的配置信息通常应该是唯一的,例如日志管理、数据库连接池等。

  • 资源访问控制:如打印机管理器、线程池、缓存管理等。

  • 全局状态管理:如游戏引擎中的场景管理、设备管理等。

2.2实际应用案例

案例1:日志管理

在应用程序中,日志系统通常是全局的,多个组件都需要访问它。如果每次记录日志都创建一个新对象,会导致资源浪费。使用单例模式可以确保日志管理器是唯一的,并可在整个程序中共享。

案例2:数据库连接池

在数据库操作中,创建和关闭数据库连接非常耗时。使用单例模式可以维护一个全局的数据库连接池,提高性能。

三、单例模式的不同实现方式

3.1懒汉式(Lazy Initialization,线程不安全)

懒汉式,在首次访问时创建实例,不适用于多线程环境,在多线程环境下可能会创建多个实例。

cpp 复制代码
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}  // 构造函数私有化

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {  // 仅在首次调用时创建
            instance = new Singleton();
        }
        return instance;
    }
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;

3.2线程安全的懒汉式

使用互斥锁确保线程安全,但会影响性能,每次访问实例都会加锁。

cpp 复制代码
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}

public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx); // 加锁
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

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

3.3双重检查锁(Double-Checked Locking)

改进线程安全的懒汉式,通过双重检查只在必要时加锁,提高性能,但在某些架构下,可能会遇到指令重排导致未正确初始化实例。

cpp 复制代码
class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {  // 第一次检查
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {  // 第二次检查
                instance = new Singleton();
            }
        }
        return instance;
    }
};

// 初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

3.4饿汉式(Eager Initialization)

在程序启动时就创建实例,避免了线程同步问题,但可能导致资源浪费。线程安全无需加锁。

cpp 复制代码
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}

public:
    static Singleton* getInstance() {
        return instance;
    }
};

// 直接初始化
Singleton* Singleton::instance = new Singleton();

3.5C++11静态局部变量

C++11保证了函数内静态变量的初始化是线程安全的,可以用它简洁高效地实现单例模式。自动管理生命周期。

cpp 复制代码
class Singleton {
private:
    Singleton() {}

public:
    static Singleton& getInstance() {
        static Singleton instance;  // 静态局部变量,线程安全
        return instance;
    }
};

四、注意事项

4.1线程安全

多线程环境下必须使用线程安全的的单例实现方式,如双重检查锁或C++11静态局部变量。

4.2内存管理

  • 手动管理的单例(懒汉式)可能会导致内存泄露,应在程序退出时释放。
  • 饿汉式单例在程序结束时由系统自动释放。

4.3禁止拷贝和赋值

为了防止创建多个实例,单例类应删除拷贝构造函数和赋值运算符

cpp 复制代码
class Singleton {
private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
};

4.4适用性

不要滥用单例,否则会导致模块间高度耦合,难以测试和维护。

适用于需要唯一实例的场景,如日志管理、线程池、数据库连接池等。

相关推荐
程序员JerrySUN14 小时前
设计模式 Day 2:工厂方法模式(Factory Method Pattern)详解
设计模式·工厂方法模式
每次的天空16 小时前
Android 单例模式全解析:从基础实现到最佳实践
android·单例模式
牵牛老人17 小时前
C++设计模式-迭代器模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
c++·设计模式·迭代器模式
诺亚凹凸曼17 小时前
23种设计模式-结构型模式-组合
设计模式
诺亚凹凸曼17 小时前
23种设计模式-结构型模式-桥接器
android·java·设计模式
xyliiiiiL18 小时前
单例模式详解
java·开发语言·单例模式
却尘21 小时前
跨域资源共享(CORS)完全指南:从同源策略到解决方案 (1)
前端·设计模式
coderzpw1 天前
设计模式中的“万能转换器”——适配器模式
设计模式·适配器模式
三金C_C1 天前
单例模式解析
单例模式·设计模式·线程锁
ShareBeHappy_Qin1 天前
设计模式——设计模式理念
java·设计模式