Singleton Pattern

Singleton Pattern trong C++ là một mẫu thiết kế (Design Pattern) đảm bảo rằng một class chỉ có duy nhất một instance trong toàn bộ chương trình và cung cấp một điểm truy cập (global access point) tới instance đó.

Trong code singleton thường có 3 phần chính :

  • constructor được dấu đi, đánh dấu private, không cho phép tạo instance trực tiếp từ bên ngoài
  • 1 biến static lưu instance duy nhất đã tạo
  • 1 hàm thường gọi là getInstance() kiểm tra nếu instance đã tồn tại thì trả về instance đó, nêu chưa thì tạo instance mới, nhờ vậy dùng gọi hàm này bao nhiêu lần chỉ nhận về đúng 1 instance duy nhất

Singleton thường dùng cho

  • Quản lý kết nối database
  • Quản lý cấu hình chương trình nơi lưu các thiết lập chung cần đồng nhất toàn hệ thống
  • Logger ghi log lỗi, cần lưu vào đúng 1 nơi, tránh phân tán nhiều files khác nhau

Singleton phù hợp khi hệ thống thực sự chỉ cần 1 đối tượng duy nhất.

Vd cả công ty có 1 máy in dùng chung, nếu ai cũng tự mua máy in riêng đặt khắp văn phòng, vừa tốn tiền, vừa lộn xộn, không ai biết file in ở máy nào, thay vào đó công ty đặt đúng 1 máy in duy nhất, ai cần in đều gửi đến máy đó, singleton hoạt động y hệt vậy, chỉ cho phép tạo đúng 1 instance duy nhất, toàn bộ chương trình dùng chung 1 instance đó.

Bạn có 1 class quản lý kết nối database, nếu không có singleton code tạo ra 3 instances khác nhau, 3 kết nối riêng biệt, tốn tài nguyên, dữ liệu không đồng bộ

/*
Không dùng Singleton
Mở 3 kết nối tới DB : tốn tài nguyên, khó quản lý, có thể vượt giới hạn số connection của DB.
db1 --> DatabaseConnection #1
db2 --> DatabaseConnection #2
db3 --> DatabaseConnection #3
*/
class DatabaseConnection {
public:
    DatabaseConnection() {
        std::cout << "Open database connection\n";
    }

    void query(const std::string& sql) {
        std::cout << "Execute: " << sql << "\n";
    }
};

int main() {
    DatabaseConnection db1;
    DatabaseConnection db2;
    DatabaseConnection db3;

    db1.query("SELECT * FROM users");
}
Open database connection
Open database connection
Open database connection
Execute: SELECT * FROM users
/*
Dùng Singleton
Ba biến đều trỏ tới cùng một object.
db1 ----\                         // std::cout << &db1 << '\n'; --> 0x7ff...
db2 -----> DatabaseConnection     // std::cout << &db2 << '\n'; --> 0x7ff...        
db3 ----/                         // std::cout << &db3 << '\n'; --> 0x7ff... 
*/
class DatabaseConnection
{
public:
    static DatabaseConnection* getInstance(){
        if (instance == NULL) {
            instance = new DatabaseConnection();
        }
        return instance;
    }

    void query(const std::string& sql) {
        std::cout << "execute: " << sql << std::endl;
    }
	
private:
    static DatabaseConnection* instance;

    // constructor riêng tư, không cho tạo instance từ bên ngoài
    DatabaseConnection() {
        std::cout << "Open database connection" << std::endl;
    }
};

int main() {
    DatabaseConnection& db1 = DatabaseConnection::getInstance();
    DatabaseConnection& db2 = DatabaseConnection::getInstance();
    DatabaseConnection& db3 = DatabaseConnection::getInstance();

    db1.query("SELECT * FROM users");
}
Open database connection
Execute: SELECT * FROM users

Leave a Comment