单例模式(懒汉式)弃
工作场景:配置文件
比如redis的配置文件redis.conf里面包涵连接数据库需要的连接信息、用户名、用户密码等配置信息,每个用户都有这个可修改的配置文件进行数据库连接个性化配置(这份文件不能写死但大体内容类似),所以需要使用设计模式思想进行代码复用,这里采将会用设计模式里的单例模式
补充:后续的代码是使用同一份配置来读取数据的场景,与上述描述有所出入,不过单例只有一个对象来控制资源的思想是通用的。
数据库配置文件复用写法(简化版)
#include <iostream>
//给用户一个config.txt文件,由用户自己修改文件需要个性化的值,只需要在当前代码中调入完成数据库的初始化配置
class SqlQuery
{
public:
    //在构造类的时候传入连接信息,用户名,密码
    SqlQuery(const std::string& conn, const std::string& username, const std::string& password)
    {
        m_conn = conn;
        m_username = username;
        m_password = password;
    }
    //一个查询数据库操作的成员函数
    int query()
    {
        // 假装这里有实现。
        return 0;
    }
    std::string m_conn;
    std::string m_username;
    std::string m_password;
};
//打开文件流的必要头文件
#include <fstream>
#include <iostream>
int main()
{
    for (int i = 0; i < 100; i++) {
        //数据库信息默认值
        std::string conn = "mysql://localhost:3306/db/";
        std::string username = "user";
        std::string password = "password";
        //一行一行的读取给用户个性化配置的文件的内容
        std::fstream fs("D://Config/config.txt");
        //读取数据的缓冲区
        char tempStr[1024];
        //当前读取数据的行数
        int index = 0;
        while (fs.getline(tempStr, 1024)) {
            if (index == 0) {
                conn = tempStr;
            }
            else if (index == 1) {
                username = tempStr;
            }
            else if (index == 2) {
                password = tempStr;
            }
            //循环读取每次加一行,直到读完
            index++;
        }
        //打印数据
        printf("conn: %s\n", conn.c_str());
        printf("username: %s\n", username.c_str());
        printf("password: %s\n", password.c_str());
        //构建对象传入参数
        SqlQuery query(conn, username, password);
        // 查询操作
        query.query();
    }
    std::cout << "C3_1\n";
}
上述传统文件配置是一种可行的方案,但存在缺点:同一用户每次连接相同的数据库的时候都需要从文件(磁盘中)中读取个性化的数据库配置文件,其实只需要保存一次或者从内存读取,否则数据库连接效率会大大降低
数据库配置文件复用写法(优化1)
//在读文件前判断是否为空,防止多次读取(优化1)
if(coon.empty()||username.empty||password.empty){
//一行一行的读取给用户个性化配置的文件的内容
        std::fstream fs("D://Config/config.txt");
        //读取数据的缓冲区
        char tempStr[1024];
        //当前读取数据的行数
        int index = 0;
        while (fs.getline(tempStr, 1024)) {
            if (index == 0) {
                conn = tempStr;
            }
            else if (index == 1) {
                username = tempStr;
            }
            else if (index == 2) {
                password = tempStr;
            }
            //循环读取每次加一行,直到读完
            index++;
        }
}
//使用全局静态变量防止变量作用域结束失去作用(优化2)
static std::string m_conn;
static std::string m_username;
static std::string m_password;
懒汉模式
只有在被静态getinstance调用的时候才创建对象初始化资源,是被动的,所以叫懒汉式
懒汉单例模式
//DBConfig.h 导入头文件
#ifndef CLIONWORK_DBCONFIG_H
#define CLIONWORK_DBCONFIG_H
#pragma once
#include <string>
class DBConfig
        {
                public:
				//管理三个成员的指针
                static DBConfig* config;
				//获取指针的方法
                static DBConfig* getInstance();
				//添加获取这三个成员变量的成员函数
                DBConfig();
				//构造函数用实现用户配置文件参数传递
                std::string getConn();
                std::string getUsername();
                std::string getPassword();
				//私有成员变量更加符合面向对象
                private:
                std::string conn;
                std::string username;
                std::string password;
        };
#endif //CLIONWORK_DBCONFIG_H
//DDBConfig.cpp
#include "DBConfig.h"
#include <fstream>
#include <iostream>
//控制一个类的指针即可管理三个成员变量
DBConfig* DBConfig::config = nullptr;
DBConfig* DBConfig::getInstance()
{
	//如果指针不为空就创建类指针
    if (config == nullptr) {
        config = new DBConfig();
    }
    return config;
}
DBConfig::DBConfig()
{
    // Read Config
    std::fstream fs("D://Config/config.txt");
    char tempStr[1024];
    int index = 0;
    while (fs.getline(tempStr, 1024)) {
        if (index == 0) {
            conn = tempStr;
        }
        else if (index == 1) {
            username = tempStr;
        }
        else if (index == 2) {
            password = tempStr;
        }
        index++;
    }
	//打印log用来判断读取文件时的操作
    printf("Read config from file\n");
}
//在源文件中加入作用域使用
std::string DBConfig::getConn()
{
    return conn;
}
std::string DBConfig::getUsername()
{
    return username;
}
std::string DBConfig::getPassword()
{
    return password;
}
//C3.2.cpp
#include <iostream>
class SqlQuery
{
public:
    SqlQuery(const std::string& conn, const std::string& username, const std::string& password)
    {
        m_conn = conn;
        m_username = username;
        m_password = password;
    }
    int query()
    {
        // 假装这里有实现。
        return 0;
    }
};
#include "DBConfig.h"
int main()
{	//循环读取操作
    for (int i = 0; i < 100; i++) {
   
        DBConfig* config = DBConfig::getInstance();
        SqlQuery query(config->getConn(), config->getUsername(), config->getPassword());
        // 查询操作
        query.query();
        printf("Query : %d\n", i);
    }
    std::cout << "C3_1\n";
}
上述代码讲解
- 如果按简化版和优化1的代码来使用这个数据库配置文件,那么如果需要在其他文件导入文件,
- 每个文件都需要判空多次浪费资源(判空集成到一个文件里)
 - 代码其他部分冗余(如果其他文件只需要这个文件的配置逻辑)
 - 频繁的创建对象浪费资源(只有一个对象(单例),来管理资源)
 - 在构造函数中执行代码逻辑
 
 - C3_2.cpp(主要流程梳理)
- 这个源文件主要是执行数据库查询逻辑,而其他两个文件是执行数据库配置文件的逻辑
 - main函数循环模拟100进行查询数据库的业务操作
 - 先通过DBConfig里的获取静态成员指针DBConfig* DBConfig(管理三个配置文件信息成员的)的成员函数getInstance获取一个实例化类对象指针并且返回(这里做判空操作不需要在其他文件进行多次判空导致浪费资源,并且保证只有一个管理成员的类对象指针(实例单例))
返回类对象指针的时候触发DBConfig里的构造函数将配置文件里的值赋值给了当前变量,然后由查询函数调用指针获取变量,最后进行查询操作。 
 
具体细节现在看也看不懂,暂时不学
单例作用以及缺点(下图简单总结)
资源共享:当多个对象需要共享同一个资源时,可以使用单例模式来管理该资源。例如,数据库连接池、线程池等。
配置信息:单例模式可以用于管理全局的配置信息,确保在整个应用程序中只有一个配置对象,方便访问和修改配置。
日志记录器:在日志记录中,使用单例模式可以确保只有一个日志记录器实例,所有的日志信息都在同一个地方进行记录,并且可以方便地访问和控制日志记录器。
缺点:单例模式虽然能够提供全局唯一的实例对象,但也有一些潜在的问题。例如,单例对象的生命周期很长,可能会导致资源持有过久;单例对象的状态共享可能引起并发访问的问题

                    
                
                
            
        
浙公网安备 33010602011771号