Language/C++

[C++] 싱글톤 패턴 (2) with C++

nowkoes 2023. 8. 10. 00:00

예제

 본문에서 구현한 예제 코드를 조금 바꿔서 main 함수에서, 그리고 다른 클래스에서 해당 클래스를 호출해 보자. 기본적으로 싱글톤으로 디자인된 인스턴스를 사용하려면 다음과 같은 코드를 입력하면 된다.

DB* db = DB::GetInstance(); // 싱글톤 클래스명* 변수명 = 싱글톤 클래스명::정적함수;

 

현재 DB에 저장되어 있는 데이터

 

 우리의 목표는 유저의 정보를 담는 User 클래스를 만들고, DB 클래스의 인스턴스를 생성해 쿼리를 작성하는 것이다. 그리고 main 함수에서도 동일하게 사용할 수 있는지 확인해 보자.

 

#include <iostream>
#include <mysql.h>
#include <vector>
#include <string>

class DB
{
    MYSQL _mysql;
    static DB* _instance;
    DB();

public:
    DB(const DB&) = delete;
    DB& operator = (const DB&) = delete;

    static DB* GetInstance();
    int GetDataCount(const std::string& query);
    void PrintUserName();
    std::vector<std::string> GetUserName();
    ~DB();
};

DB* DB::_instance = nullptr;

DB* DB::GetInstance()
{
    if (_instance == nullptr)
        _instance = new DB();

    return _instance;
}

DB::DB()
{
    mysql_init(&_mysql);

    if (!mysql_real_connect(&_mysql, "localhost", "root", "password", "example", 3306, NULL, 0))
    {
        std::cerr << "Failed to connect to MySQL\n";
        return;
    }

    else
        std::cout << "Successfully Connected with MySQL\n";
}

int DB::GetDataCount(const std::string& query)
{
    if (mysql_query(&_mysql, query.c_str()))
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";

    MYSQL_RES* result = mysql_store_result(&_mysql);
    int count = -1;

    if (result)
    {
        MYSQL_ROW row = mysql_fetch_row(result);
        count = std::stoi(row[0]);
        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";

    return count;
}

void DB::PrintUserName()
{
    std::string query = "SELECT name FROM example_table";

    if(mysql_query(&_mysql, query.c_str()))
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";

    MYSQL_RES* result = mysql_store_result(&_mysql);

    if (result)
    {
        MYSQL_ROW row;

        while ((row = mysql_fetch_row(result)))
            std::cout << row[0] << std::endl; // name 컬럼의 값을 출력
        
        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";
}

std::vector<std::string> DB::GetUserName()
{
    std::vector<std::string> names;
    std::string query = "SELECT name FROM example_table";

    if (mysql_query(&_mysql, query.c_str()))
    {
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";
        return names;
    }

    MYSQL_RES* result = mysql_store_result(&_mysql);

    if (result)
    {
        MYSQL_ROW row;

        while ((row = mysql_fetch_row(result)))
            names.push_back(row[0]);

        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";

    return names;
}

DB::~DB()
{
    mysql_close(&_mysql);
}

 해당 기능을 구현하기 위해 DB 클래스에 유저 수를 반환하는 GetDataCount 메서드, 유저의 이름을 출력하는 PrintUserName 메서드, 유저의 이름들을 반환하는 GetUserName 메서드를 추가하였다.

 

 이제 User라는 클래스를 만들어 MySQL 데이터베이스에 있는 유저의 정보를 받아와, name이라는 배열에 이름을 담는 코드를 작성해 보자. DB에 database의 이름은 example, 테이블은 example_table이라고 가정하겠다. 

class User
{
    std::vector<std::string> _names;
    int _head_count;

public:
    User();
    void PrintUser();
};

User::User()
{
    DB* db = DB::GetInstance();

    std::string query = "SELECT COUNT(*) FROM example_table";
    _head_count = db->GetDataCount(query);
    _names.reserve(_head_count);
    _names = db->GetUserName();
    
}

void User::PrintUser()
{
    for (const auto& str : _names)
        std::cout << str << " ";
    std::cout << "\n";
}

 유저의 이름을 담는 배열 _names, 인원수를 담는 정수 _head_count를 선언하고, 생성자와 인스턴스를 통해 각각의 변수를 초기화시켰다. 그리고 PrintUser 멤버 함수를 호출했을 때 벡터에 있는 원소들을 출력하게 구현하였다.

 

int main() 
{
    DB* db = DB::GetInstance();
    db->PrintUserName();

    User user;
    user.PrintUser();
}

출력

 

 정상적으로 작동하는 것을 확인할 수 있다.

 

총합본

더보기
#include <iostream>
#include <mysql.h>
#include <vector>
#include <string>

class DB
{
    MYSQL _mysql;
    static DB* _instance;
    DB();

public:
    DB(const DB&) = delete;
    DB& operator = (const DB&) = delete;

    static DB* GetInstance();
    int GetDataCount(const std::string& query);
    void PrintUserName();
    std::vector<std::string> GetUserName();
    ~DB();
};

DB* DB::_instance = nullptr;

DB* DB::GetInstance()
{
    if (_instance == nullptr)
        _instance = new DB();

    return _instance;
}

DB::DB()
{
    mysql_init(&_mysql);

    if (!mysql_real_connect(&_mysql, "localhost", "root", "password", "example", 3306, NULL, 0))
    {
        std::cerr << "Failed to connect to MySQL\n";
        return;
    }

    else
        std::cout << "Successfully Connected with MySQL\n";
}

int DB::GetDataCount(const std::string& query)
{
    if (mysql_query(&_mysql, query.c_str()))
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";

    MYSQL_RES* result = mysql_store_result(&_mysql);
    int count = -1;

    if (result)
    {
        MYSQL_ROW row = mysql_fetch_row(result);
        count = std::stoi(row[0]);
        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";

    return count;
}

void DB::PrintUserName()
{
    std::string query = "SELECT name FROM example_table";

    if(mysql_query(&_mysql, query.c_str()))
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";

    MYSQL_RES* result = mysql_store_result(&_mysql);

    if (result)
    {
        MYSQL_ROW row;

        while ((row = mysql_fetch_row(result)))
            std::cout << row[0] << std::endl; // name 컬럼의 값을 출력
        
        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";
}

std::vector<std::string> DB::GetUserName()
{
    std::vector<std::string> names;
    std::string query = "SELECT name FROM example_table";

    if (mysql_query(&_mysql, query.c_str()))
    {
        std::cerr << "Query Error: " << mysql_error(&_mysql) << "\n";
        return names;
    }

    MYSQL_RES* result = mysql_store_result(&_mysql);

    if (result)
    {
        MYSQL_ROW row;

        while ((row = mysql_fetch_row(result)))
            names.push_back(row[0]);

        mysql_free_result(result);
    }

    else
        std::cerr << "Store result error: " << mysql_error(&_mysql) << "\n";

    return names;
}

DB::~DB()
{
    mysql_close(&_mysql);
}

class User
{
    std::vector<std::string> _names;
    int _head_count;

public:
    User();
    void PrintUser();
};

User::User()
{
    DB* db = DB::GetInstance();

    std::string query = "SELECT COUNT(*) FROM example_table";
    _head_count = db->GetDataCount(query);
    _names.reserve(_head_count);
    _names = db->GetUserName();
    
}

void User::PrintUser()
{
    for (const auto& str : _names)
        std::cout << str << " ";
    std::cout << "\n";
}

int main() 
{
    DB* db = DB::GetInstance();
    db->PrintUserName();

    User user;
    user.PrintUser();
}
반응형