1、跟学23种设计模式(C++版):单例模式

单例模式(Singleton Pattern)用于确保一个类只有一个实例,并提供全局访问点。它的主要目的是控制实例的创建,以便于在整个程序中共享相同的实例。

单例模式的特点

1、 唯一实例:确保某个类只有一个实例;
2、 全局访问点:提供一个访问该实例的全局访问点;

实现单例模式的步骤

1、 私有化构造函数:防止外界通过构造函数创建实例;
2、 静态成员变量:用于保存单例实例的指针;
3、 静态公有方法:用于返回单例实例的指针;

单例模式适用于以下场景:

1、 全局配置管理:如读取配置文件后,全局共享配置对象;
2、 日志系统:日志对象在系统中应当是唯一的,避免多实例导致混乱;
3、 资源管理:如线程池、数据库连接池等,确保资源的全局唯一性和统一管理;
4、 缓存:如应用程序级缓存,保证缓存数据的一致性;

常见的实现方式有懒汉模式和饿汉模式。本文将详细介绍这两种模式,并通过类图和实际案例来说明其应用。

懒汉模式(Lazy Initialization)

懒汉模式指的是在需要使用实例时才进行实例化。它的优点是只有在第一次使用时才创建实例,节省资源,但缺点是需要注意线程安全问题。

懒汉模式实现:

#include <iostream>
#include <mutex>

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

    // 私有化构造函数
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 禁止拷贝构造和赋值运算符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 静态公有方法获取单例实例
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

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

int main() {
    Singleton* s1 = Singleton::getInstance();
    s1->showMessage();

    Singleton* s2 = Singleton::getInstance();
    s2->showMessage();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }

    return 0;
}

饿汉模式(Eager Initialization)

饿汉模式指的是在类加载时就进行实例化。它的优点是线程安全,简单,但缺点是无论实例是否会用到,都在程序启动时创建实例,可能浪费资源。

饿汉模式实现:

#include <iostream>

class Singleton {
private:
    // 静态实例在类加载时创建
    static Singleton* instance;

    // 私有化构造函数
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 禁止拷贝构造和赋值运算符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 静态公有方法获取单例实例
    static Singleton* getInstance() {
        return instance;
    }

    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// 初始化静态成员
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* s1 = Singleton::getInstance();
    s1->showMessage();

    Singleton* s2 = Singleton::getInstance();
    s2->showMessage();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }

    return 0;
}

类图对比:

*

实际案例

日志系统(懒汉模式)

#include <iostream>
#include <fstream>
#include <mutex>

class Logger {
private:
    static Logger* instance;
    static std::mutex mtx;
    std::ofstream logFile;

    // 私有化构造函数
    Logger() {
        logFile.open("log.txt", std::ios::app);
    }

public:
    // 析构函数
    ~Logger() {
        if (logFile.is_open()) {
            logFile.close();
        }
    }

    // 禁止拷贝构造和赋值运算符
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    // 静态公有方法获取单例实例
    static Logger* getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Logger();
        }
        return instance;
    }

    // 日志记录方法
    void log(const std::string& message) {
        std::lock_guard<std::mutex> lock(mtx);
        if (logFile.is_open()) {
            logFile << message << std::endl;
        }
    }
};

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

int main() {
    Logger* logger = Logger::getInstance();
    logger->log("Application started");
    logger->log("An error occurred");

    return 0;
}

配置管理器(饿汉模式)

#include <iostream>
#include <string>

class ConfigManager {
private:
    // 静态实例指针
    static ConfigManager* instance;
    // 配置值
    std::string configValue;

    // 私有化构造函数,防止外部实例化
    ConfigManager() {
        // 假设读取配置文件
        configValue = "Initial Config";
        std::cout << "ConfigManager instance created." << std::endl;
    }

public:
    // 禁止拷贝构造和赋值运算符
    ConfigManager(const ConfigManager&) = delete;
    ConfigManager& operator=(const ConfigManager&) = delete;

    // 静态公有方法获取单例实例
    static ConfigManager* getInstance() {
        return instance;
    }

    // 获取配置值
    std::string getConfig() {
        return configValue;
    }

    // 设置配置值
    void setConfig(const std::string& value) {
        configValue = value;
    }
};

// 初始化静态成员
ConfigManager* ConfigManager::instance = new ConfigManager();

int main() {
    // 获取单例实例
    ConfigManager* config = ConfigManager::getInstance();

    // 输出初始配置值
    std::cout << "Config: " << config->getConfig() << std::endl;

    // 更新配置值
    config->setConfig("Updated Config");

    // 输出更新后的配置值
    std::cout << "Config: " << config->getConfig() << std::endl;

    return 0;
}

总结

懒汉模式和饿汉模式各有优缺点,具体选择应根据应用场景和实际需求来决定。在实际开发中,单例模式广泛应用于全局配置管理、日志系统、资源管理等场景,确保全局实例的唯一性和一致性。

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: