当前位置: 首页 > article >正文

设计模式--单例模式(Singleton)【C++】

引言

在设计模式中,单例模式(Singleton Pattern)是一种非常常见且实用的模式。它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这种模式在需要全局唯一对象的场景中非常有用,比如配置管理、日志记录、数据库连接池等。

本文将通过一个简单的 C++ 示例,带你理解单例模式的基本概念和实现方法。即使你是设计模式的新手,也能轻松掌握!


什么是单例模式?

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。它的主要特点包括:

  1. 唯一性:整个程序中只有一个实例存在。
  2. 全局访问:通过一个静态方法或变量来访问该实例。

单例模式的核心思想是通过控制类的实例化过程,避免外部代码随意创建多个实例。


为什么需要单例模式?

在某些场景中,我们需要确保一个类只有一个实例。例如:

  • 配置管理:程序的配置信息只需要加载一次,全局共享。
  • 日志记录:日志系统只需要一个实例来记录所有日志。
  • 数据库连接池:数据库连接池只需要一个实例来管理所有连接。

如果这些场景中允许多个实例存在,可能会导致资源浪费或数据不一致的问题。

C++实现单例模式

先从简单的单例模式入手,通过简单的锁机制实现单例

#include <iostream>
#include <mutex>

class Singleton {
protected:
    Singleton() = default;//禁止外部构造
    Singleton(const Singleton&) = delete;//禁止外部拷贝构造
    ~Singleton() { std::cout << "~Singleton" << std::endl; }//禁止外部析构
    Singleton& operator=(const Singleton&) = delete;//禁止外部赋值
    static Singleton* _instance;//单例对象指针
    static std::mutex s_mutex; //互斥锁

public:
    //获取单例实例
    static Singleton* GetInstance() {//通过双重检查实现单例
        if (_instance == nullptr) {
            std::lock_guard<std::mutex> lock(s_mutex);//加锁
            if (_instance == nullptr) {
                _instance = new Singleton();//初始化单例对象
            }
        }
        return _instance;
    }
    //打印单例实例地址
    void PrintAddress() { std::cout << _instance << std::endl; }
};
//初始化静态成员变量
Singleton* Singleton::_instance = nullptr;
std::mutex Singleton::s_mutex;

int main() {
    Singleton* singleton1 = Singleton::GetInstance();
    singleton1->PrintAddress();
    Singleton* singleton2 = Singleton::GetInstance();
    singleton2->PrintAddress();
    std::cout << "Address: " << singleton1 << std::endl;
    std::cout << "Address: " << singleton2 << std::endl;
    return 0;
}

通过这个例子,你会发现singleton1和singleton2的地址相同

如果我们想通过单例模式来创建其他类实例,需要引入模板,参考下列代码。

假设我们需要创建一个Redis连接池,通过单例模式实现可以确保一个实例管理所有链接

#include <iostream>
#include <memory>
#include <mutex>
class RedisConPool : public Singleton<RedisConPool>{
    friend class Singleton<RedisConPool>;//允许Singleton访问Redis的私有成员
private:
    Redis(){std::cout << "RedisConPool instance created!" << std::endl;}
    ~Redis(){std::cout << "RedisConPool instance destroyed!" << std::endl;}
};
template<typename T>
class Singleton {
protected:
    Singleton() = default;//禁止外部构造
    Singleton(const Singleton<T>&) = delete;//禁止外部拷贝构造
    ~Singleton() { std::cout << "~Singleton" << std::endl; }//禁止外部析构
    Singleton<T>& operator=(const Singleton<T>&) = delete;//禁止外部赋值
    static std::shared_ptr<T> _instance;//单例对象智能指针
    static std::once_flag s_flag;//保证单例对象只被初始化一次
public:
    //获取单例实例
    static std::shared_ptr<T> GetInstance() {
        std::claa_once(s_flag,[&]() {
            _instance = std::shared_ptr<T>(new T);//初始化单例对象
        });
        return _instance;
    }
    //打印单例实例地址
    void PrintAddress() { std::cout << _instance.get() << std::endl; }

};
//初始化静态成员变量
template<typename T>
std::shared_ptr<T> Singleton<T>::_instance = nullptr;
template<typename T>
std::once_flag Singleton<T>::s_flag;

int main() {
    //获取单例实例
    std::shared_ptr<RedisConPool> redis1 = Singleton<RedisConPool>::GetInstance();
    std::shared_ptr<RedisConPool> redis2 = Singleton<RedisConPool>::GetInstance();
    redis1->PrintAddress();
    redis2->PrintAddress();
    //比较两个单例实例的地址
    std::cout << "redis1 == redis2 ? " << (redis1 == redis2) << std::endl;
    return 0;
}

通过引入模板和智能指针单例类可以更方便的管理仅需一个实例的类

 


http://www.kler.cn/a/576312.html

相关文章:

  • 分布式存储学习——HBase概述
  • linux上安装redis[从0到1]
  • Jenkins在Windows上的使用(二):自动拉取、打包、部署
  • 【uniapp】图片添加canvas水印
  • FFmpeg入门:最简单的音视频播放器
  • Docker 部署
  • 六、Redis 高级功能详解:BitMap、HyperLogLog、Geo、Stream
  • Webpack、Parcel、Rollup、esbuild、Vite、Next.js前端构建工具
  • 分布式泵站无线统管终极方案:1站1机,GRM242Q-C集群直通中控大屏(老型号GRM232Q-C)
  • 米尔基于STM32MP25x核心板Debian系统发布,赋能工业设备
  • 轻闪PDF(Windows傲软PDF编辑软件)2.15.2中文安装版
  • 重塑未来:生成式AI如何重构企业数据基因?三大技术重构的生死局
  • Swift系列01-Swift语言基本原理与设计哲学
  • T31ZC 君正SOC芯片 应用于智能家居、工业控制等 满足各种嵌入式应用的需求 提供样品测试+软硬件资料
  • 奇安信 2025 年护网蓝队初选笔试题(附答案解析)
  • 物联网 全部技术栈和实现方案
  • vue3中emits
  • Linux15-epoll、数据库
  • 数据库复习(第五版)- 第十一章 并发控制
  • 【js逆向】图灵爬虫练习平台 第十五题