C++ Singleton设计模式怎么实现?

文章导读
Previous Quiz Next Singleton Pattern 是一种设计模式,它允许创建一个 class 的唯一对象。它不允许多次调用时创建多个实例,而是确保 class 只创建一个实例,并提供一个全局访问点,以便在代码的任何地方都能访问它。
📋 目录
  1. A Singleton Pattern 的关键点
  2. B C++ 中 Singleton Pattern 的实现
  3. C Lazy Initialization Singleton
  4. D 急切初始化单例(饥饿单例)实现
  5. E Meyers' 单例实现
  6. F 单例模式在实际中的使用场景
  7. G 结论
A A

C++ 中的单例模式



Previous
Quiz
Next

Singleton Pattern 是一种设计模式,它允许创建一个 class 的唯一对象。它不允许多次调用时创建多个实例,而是确保 class 只创建一个实例,并提供一个全局访问点,以便在代码的任何地方都能访问它。

当系统中需要恰好一个对象来协调各项操作时,singleton pattern 就很有用。例如,想象你在办公室需要使用打印机。与其为每个员工配备一台打印机,不如使用一台所有员工共享的打印机。这样可以确保同一时间只有一个人使用打印机,同时还能节省资源。

Singleton Pattern 的关键点

Singleton Pattern 的关键点如下 −

  • 它将 class 的实例化限制为单个实例。
  • 它为该实例提供全局访问点。
  • 它常用于管理共享资源,如数据库连接、配置设置、日志记录等。
  • 它可以使用 lazy initialization 实现,即实例仅在首次需要时才创建。

C++ 中 Singleton Pattern 的实现

C++ 中实现 Singleton Pattern 有多种方式。一些重要且常用的实现包括 −

  • Lazy Initialization Singleton
  • Eager Initialization Singleton (Hungry Singleton)
  • Mayers' Singleton

大多数情况下使用 lazy initialization singleton,因为它更高效且节省内存。不过,eager initialization singleton 更简单且是 thread-safe 的。Mayers' singleton 实现是 C++ 中创建 singleton class 的优秀现代方法。

Lazy Initialization Singleton

在这种方法中,class 的实例仅在首次需要时才创建。这有助于只创建 class 的一个实例,同时节省内存。

C++ 中实现 Singleton Pattern 的步骤

C++ 中实现 Singleton Pattern 的步骤如下 −

  • 将 class 的 constructor 设为 private,以防止从 class 外部实例化。
  • 然后,创建一个 static 变量来保存 class 的单个实例。
  • 创建一个 static 方法返回 class 的实例。该方法检查实例是否已创建,如果未创建则创建一个并返回;否则,直接返回现有实例。

C++ 中 Singleton Pattern 示例

在下面的示例中,我们有一个 Logger class 实现了 singleton pattern。getInstance() 方法返回 Logger class 的单个实例。log() 方法用于记录消息。

让我们使用 Singleton Pattern 在 C++ 中实现一个简单的 Logger class。

#include <iostream>
#include <string>
using namespace std;
// Logger 的 Lazy Initialization Singleton
class Logger {
   private:
      static Logger* instance;
      Logger() {} 
   
   public:
      static Logger* getInstance() {
         if (instance == nullptr) {
            instance = new Logger();
         }
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
// 初始化静态成员
Logger* Logger::instance = nullptr;

// 主函数
int main() {
   Logger* logger = Logger::getInstance();
   logger->log("This is a log message.");
   Logger* l1 = Logger::getInstance();
   l1->log("This is another log message.");
   return 0;
}

以上程序的输出如下 −

Log: This is a log message.
Log: This is another log message.

急切初始化单例(饥饿单例)实现

在这种方法中,我们在类加载时创建类的实例。这种方法更简单,并且是线程安全的。然而,这种方法的缺点是即使实例未被使用,也会创建实例,这可能导致资源浪费。因此,如果您确定实例会被使用,这种方法是一个不错的选择。

C++ 中急切初始化单例模式的示例

让我们使用 C++ 中的急切初始化单例模式实现一个简单的 Logger 类。

#include <iostream>
#include <string>
using namespace std;

// Logger 的急切初始化单例
class Logger {
   private:
      static Logger* instance;
      Logger() {} 
   
   public:
      static Logger* getInstance() {
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
// 在类加载时初始化实例
Logger* Logger::instance = new Logger();

// 主函数
int main() {
   Logger* logger = Logger::getInstance();
   logger->log("This is a log message.");
   Logger* l1 = Logger::getInstance();
   l1->log("This is another log message.");
   return 0;
}

以上程序的输出如下 −

Log: This is a log message.
Log: This is another log message.

Meyers' 单例实现

Meyers' 单例实现是 C++ 中创建单例类的一种非常好的现代方法。这种方法在 getInstance() 方法中使用静态局部变量来保存类的单个实例。实例在方法第一次被调用时创建,并在程序退出时自动销毁。这种方法是线程安全的,并且确保只创建一个类的实例。

C++ 中 Meyers' 单例模式的示例

让我们使用 C++ 中的 Meyers' 单例模式实现一个简单的 Logger 类。

#include <iostream>
#include <string>
using namespace std;

// Logger 的 Meyers' 单例
class Logger {
   private:
      Logger() {} 
   
   public:
      static Logger& getInstance() {
         static Logger instance;
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
// 主函数
int main() {
   Logger& logger = Logger::getInstance();
   logger.log("This is a log message.");
   Logger& l1 = Logger::getInstance();
   l1.log("This is another log message.");
   return 0;
}

以上程序的输出如下 −

Log: This is a log message.
Log: This is another log message.

单例模式在实际中的使用场景

以下是单例模式的一些实际使用场景 −

  • Logger 类 − 如示例所示,Logger 类使用单例模式,因此可以在任何地方访问,但整个应用程序只创建一个实例。
  • 配置类 − 配置类可以实现为单例,以确保整个应用程序中只有一个配置设置的实例。
  • 数据库连接类 − 另一个使用场景是实现数据库连接类,这样就不需要创建多个数据库连接。
  • 打印假脱机 − 打印假脱机可以实现为单例,以集中管理打印作业。因此,整个系统只有一个打印假脱机的实例,而不是为系统上的每个应用程序创建多个实例。

结论

在本章中,我们详细介绍了 C++ 中的 Singleton Pattern。我们解释了如何实现它,并提供了一个使用 singleton pattern 的 Logger class 示例。Singleton pattern 是一种有用的设计模式,它有助于管理共享资源,并确保 class 只创建一个实例。