设计模式——单例模式

C++ 单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。

一、单例模式的主要特点和目的

单一实例:

单例模式的核心特点是在整个程序的生命周期中,一个类只有一个实例被创建。无论在程序的哪个部分尝试获取该类的实例,都将得到同一个对象。

这对于一些需要全局唯一资源的场景非常有用,例如数据库连接管理器、配置文件读取器、日志记录器等。这些对象在整个程序中只需要一个实例来管理相关资源,避免了资源的重复分配和冲突。

全局访问点:

提供一个静态方法或全局函数,允许在程序的任何地方方便地访问单例对象。通常这个方法被命名为 getInstance()。

这种全局访问的方式使得单例对象可以在不同的模块和函数之间共享,而无需通过复杂的参数传递或对象引用传递。

控制资源访问和共享:

单例模式可以有效地控制对某些关键资源的访问。例如,一个数据库连接管理器单例可以确保所有的数据库操作都使用同一个连接,避免了频繁地创建和销毁连接所带来的开销。

同时,单例对象可以在不同的部分之间共享数据和状态,实现了一种简洁的信息传递方式。

二、单例模式的实现方式

懒汉式(Lazy Initialization):

在第一次调用获取实例的方法时才创建单例对象。

优点是只有在实际需要的时候才创建对象,避免了不必要的资源浪费。但是,这种方式在多线程环境下可能会出现问题,因为多个线程可能同时判断实例是否为 nullptr,并尝试创建实例,导致创建多个实例。

以下是懒汉式单例的示例代码:

cpp 复制代码
   class Singleton {
   private:
       static Singleton* instance;
       Singleton() {}
   public:
       static Singleton* getInstance() {
           if (instance == nullptr) {
               instance = new Singleton();
           }
           return instance;
       }
   };

   Singleton* Singleton::instance = nullptr;

饿汉式(Eager Initialization):

在程序启动时就创建单例对象。

优点是线程安全,因为对象在程序启动时就已经创建好了,不存在多线程竞争的问题。缺点是如果单例对象的创建比较耗时或者占用较多资源,可能会影响程序的启动性能。

以下是饿汉式单例的示例代码:

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

   Singleton* Singleton::instance = new Singleton();

线程安全的懒汉式(Thread-Safe Lazy Initialization):

使用互斥锁或其他线程同步机制来确保在多线程环境下只有一个实例被创建。

以下是使用互斥锁实现的线程安全懒汉式单例的示例代码:

cpp 复制代码
   #include <mutex>

   class Singleton {
   private:
       static Singleton* instance;
       static std::mutex mutex_instance;
       Singleton() {}
   public:
       static Singleton* getInstance() {
           std::lock_guard<std::mutex> lock(mutex_instance);
           if (instance == nullptr) {
               instance = new Singleton();
           }
           return instance;
       }
   };

   Singleton* Singleton::instance = nullptr;
   std::mutex Singleton::mutex_instance;

三、单例模式的应用场景

资源管理:

如数据库连接管理器、文件系统访问器等。这些资源通常需要在整个程序中共享,并且只需要一个实例来管理它们的连接和状态。

例如,数据库连接管理器单例可以确保所有的数据库操作都使用同一个连接,避免了频繁地创建和销毁连接所带来的开销。

配置管理:

配置文件读取器单例可以在程序启动时读取配置文件,并在整个程序中提供对配置信息的全局访问。这样可以避免在多个地方重复读取配置文件,提高程序的性能和可维护性。

日志记录:

日志记录器单例可以在整个程序中记录日志信息,确保所有的日志都被写入到同一个文件或输出到同一个控制台。这样可以方便地管理和查看程序的日志信息。

全局状态管理:

在一些复杂的程序中,可能需要一个全局的状态管理器来跟踪程序的状态。单例模式可以用于实现这样的状态管理器,确保在整个程序中只有一个状态管理器实例,方便地管理和共享程序的状态信息。

四、单例模式的优缺点

优点:

单一实例控制:确保一个类只有一个实例,避免了资源的重复分配和冲突。

全局访问:提供了一个方便的全局访问点,使得单例对象可以在程序的任何地方被访问。

易于管理:由于只有一个实例,所以对资源的管理更加简单和高效。

缺点:

违反单一职责原则:

单例类既负责创建和管理自身的实例,又负责提供业务逻辑。这可能导致单例类的职责过于复杂,难以维护和扩展。

测试困难:

由于单例对象在程序中全局可见,并且通常在程序启动时就被创建,这使得对使用单例的代码进行单元测试变得困难。测试时可能需要对单例对象进行模拟或替换,这需要一些额外的技巧和工具。

可能导致内存泄漏:

如果单例对象在程序的整个生命周期中都存在,并且没有正确地释放资源,可能会导致内存泄漏。特别是在长时间运行的程序中,这可能会成为一个问题。

总的来说,C++ 单例模式是一种非常有用的设计模式,它可以在很多场景下提供方便的资源管理和全局访问。但是,在使用单例模式时,需要注意其优缺点,并根据具体的应用场景进行合理的设计和实现。

相关推荐
Tt有了t1 天前
设计模式速查
java·python·设计模式
一条Go1 天前
四个进程,一把锁:Alioth 的告警评测为什么不需要消息队列
后端·设计模式·架构
一缕82年的清风1 天前
被中产唾弃的“十元快剪”,藏着最狠的极客工程学
人工智能·设计模式
是2的10次方啊1 天前
设计模式与生活⑫:周报又到手,别从空白开始
设计模式
拆房老料2 天前
DeepSeek Super-agent 架构解析:从单任务 Agent 到持续运行的任务系统
人工智能·设计模式·系统架构
工一木子2 天前
设计模式与生活⑩:地铁没变,你换了个状态
设计模式
是2的10次方啊2 天前
设计模式与生活⑪:地铁里被打扰,别总靠自己硬扛
设计模式
高晶3 天前
SPMI 控制器 RTL 设计与验证新手入门
设计模式·程序员·架构
geovindu3 天前
rust:N-Barrier Pattern
开发语言·后端·设计模式·rust·屏障模式·并发型模式
顧棟3 天前
OpenAPI 网关:鉴权 + 流量治理 一体化设计方案与实现
java·spring boot·设计模式