[ Better ] Sử dụng Singleton Pattern trong javascript ES6

Avatar admin | June 1, 2024

Singleton Pattern là một mẫu thiết kế được sử dụng để hạn chế số lượng đối tượng có thể được
hiển thị trong một lớp đối tượng.

Điều này có nghĩa là thay vì tạo ra một đối tượng mới,
bất kỳ lần khởi tạo sau đó của lớp đó sẽ trả về thể hiện đã tồn tại.

Singleton Pattern

Khi cần kiểm soát truy cập đến một tài nguyên chỉ có một thể hiện, chẳng hạn như khi kết nối với
bộ nhớ đệm, cơ sở dữ liệu hoặc thiết bị ngoại vi, Singleton Pattern thường được sử dụng.

Xem thêm BaseServices OOP với User

Cách triển khai Singleton Pattern trong JavaScript là như sau:

class Singleton {
    constructor() {
        if (Singleton.instance) {
            return Singleton.instance;
        }
        
        this.data = "Some data";
        Singleton.instance = this;
    }
    
    getData() {
        return this.data;
    }

    setData(data) {
        this.data = data;
    }
}

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
console.log(instance1.getData()); // "Some data"
instance1.setData("New data");
console.log(instance2.getData()); // "New data"

Singleton Pattern Sử dụng Khóa


Closure để bảo vệ thể hiện duy nhất là một phương pháp bổ sung để triển khai Singleton Pattern trong
JavaScript.

// singleton.js
class Singleton {
    constructor() {
        if (!Singleton.instance) {
            this.data = "Some data";
            Singleton.instance = this;
        }
        
        return Singleton.instance;
    }

    getData() {
        return this.data;
    }

    setData(data) {
        this.data = data;
    }
}

const instance = new Singleton();
Object.freeze(instance);

export default instance;

Các sử dụng

// main.js
import instance1 from './singleton.js';
import instance2 from './singleton.js';

console.log(instance1 === instance2); // true
console.log(instance1.getData()); // "Some data"
instance1.setData("New data");
console.log(instance2.getData()); // "New data"

Với các cách triển khai trên, bạn có thể dễ dàng áp dụng Singleton Pattern trong JavaScript để đảm bảo
rằng chỉ có một thể hiện của lớp được tạo ra trong suốt quá trình hoạt động của ứng dụng.

Xem thêm: Phong cách lập trình là như nào

Có nhiều lợi ích khi sử dụng Singleton Pattern, đặc biệt là trong các hệ thống phần mềm lớn và phức tạp.

  1. Kiểm soát truy cập đến tài nguyên duy nhất
    Singleton đảm bảo rằng chỉ có một thể hiện duy nhất của một lớp tồn tại, giúp kiểm soát truy cập đến tài nguyên mà chỉ cần một thể hiện, chẳng hạn như kết nối cơ sở dữ liệu, file cấu hình, hay bộ nhớ đệm.
  2. Tiết kiệm tài nguyên hệ thống
    Bằng cách giới hạn số lượng thể hiện của một lớp, Singleton giúp tiết kiệm tài nguyên hệ thống như bộ nhớ và CPU. Điều này đặc biệt hữu ích khi việc khởi tạo đối tượng tốn kém về mặt tài nguyên.
  3. Hỗ trợ các global variables
    Singleton có thể thay thế các biến toàn cục bằng cách cung cấp một cách tiếp cận có cấu trúc hơn. Thay vì sử dụng các biến toàn cục dễ gây xung đột và khó quản lý, bạn có thể sử dụng các phương thức của Singleton để truy cập các tài nguyên dùng chung.
  4. Dễ dàng tích hợp với các pattern khác
    Singleton thường được sử dụng cùng với các mẫu thiết kế khác như Factory Pattern, Builder Pattern, và Facade Pattern để xây dựng các hệ thống phức tạp và mạnh mẽ hơn.
  5. Tính nhất quán trong ứng dụng
    Singleton giúp đảm bảo tính nhất quán trong ứng dụng khi mọi phần của hệ thống đều sử dụng cùng một thể hiện của đối tượng Singleton.

Ví dụ về lợi ích của Singleton

Một ví dụ điển hình về việc sử dụng Singleton là trong việc quản lý kết nối cơ sở dữ liệu.

Nếu mỗi lần bạn truy cập cơ sở dữ liệu bạn tạo một kết nối mới, điều này có thể dẫn đến tình trạng quá tải và hiệu suất kém.

Thay vào đó, bạn có thể sử dụng Singleton để đảm bảo rằng chỉ một kết nối duy nhất được sử dụng cho tất cả các truy vấn cơ sở dữ liệu:

class DatabaseConnection {
    constructor() {
        if (!DatabaseConnection.instance) {
            this.connection = this.connectToDatabase();
            DatabaseConnection.instance = this;
        }
        return DatabaseConnection.instance;
    }

    connectToDatabase() {
        // Giả sử đây là mã để kết nối đến cơ sở dữ liệu
        return "Database connection established";
    }

    getConnection() {
        return this.connection;
    }
}

const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();

console.log(db1.getConnection()); // "Database connection established"
console.log(db1 === db2); // true

Với đoạn code trên thì Database chỉ được khởi tạo 1 lần từ lúc mở ứng dụng cho đến khi ứng dụng tắt đi mà không tốn thêm tài nguyên mỗi lần truy vấn

Singleton Pattern trong kế thừa

Trong JavaScript, bạn có thể tạo một lớp cơ sở Singleton cũng như các lớp con kế thừa từ nó để kết hợp hình thức kế thừa với hình thức Singleton.

Điều này cho phép duy trì tính chất Singleton mà vẫn tận dụng tính kế thừa và đa hình trong OOP.

Đây là một ví dụ cụ thể:

Lớp cơ sở đơn lẻ
Chúng ta sẽ bắt đầu bằng việc tạo một lớp cơ sở Singleton. Lớp này sẽ đảm bảo rằng chỉ tạo ra một thể hiện của lớp hoặc các lớp con của nó.

class Singleton {
    constructor() {
        if (this.constructor.instance) {
            return this.constructor.instance;
        }

        this.constructor.instance = this;
    }
}

Lớp trưởng thành của Singleton
Chúng tôi sẽ tiếp tục tạo các lớp con kế thừa của lớp cơ sở Singleton.

class DatabaseConnection extends Singleton {
    constructor(connectionString) {
        super();
        if (!DatabaseConnection.instance) {
            this.connectionString = connectionString;
            this.connection = this.connectToDatabase();
        }
        return DatabaseConnection.instance;
    }

    connectToDatabase() {
        // Mã giả lập kết nối cơ sở dữ liệu
        return `Database connected with ${this.connectionString}`;
    }

    getConnection() {
        return this.connection;
    }
}

class APIService extends Singleton {
    constructor(apiEndpoint) {
        super();
        if (!APIService.instance) {
            this.apiEndpoint = apiEndpoint;
            this.connection = this.connectToAPI();
        }
        return APIService.instance;
    }

    connectToAPI() {
        // Mã giả lập kết nối đến API
        return `API connected to ${this.apiEndpoint}`;
    }

    getConnection() {
        return this.connection;
    }
}

Cách sử dụng các lớp con Singleton


Bây giờ chúng ta có thể kiểm tra tính chất Singleton và tạo các thể hiện của các lớp con.

const db1 = new DatabaseConnection("mongodb://localhost:27017/myapp");
const db2 = new DatabaseConnection("mongodb://localhost:27017/otherapp");

console.log(db1 === db2); // true
console.log(db1.getConnection()); // "Database connected with mongodb://localhost:27017/myapp"

const api1 = new APIService("https://api.example.com");
const api2 = new APIService("https://api.other.com");

console.log(api1 === api2); // true
console.log(api1.getConnection()); // "API connected to https://api.example.com"

Lớp con DatabaseConnection và APIService: Những lớp con này kế thừa từ lớp Singleton và có các phương thức và thuộc tính riêng biệt.


Tìm hiểu tính chất của Singleton: Chúng tôi phát hiện ra rằng khi chúng tôi tạo nhiều thể hiện cho DatabaseConnection và APIService, mỗi lớp chỉ có một thể hiện, ngay cả khi chúng tôi cố gắng khởi tạo lại chúng với các tham số khác nhau.


Ví dụ này minh họa cách bạn có thể kết hợp cấu trúc Singleton với kế thừa trong JavaScript để đảm bảo rằng chỉ có một thể hiện.

#mtips5s contact

Fanpage: https://www.facebook.com/mtips5s

Group trao đổi, chia sẻ: https://www.facebook.com/groups/mtips5s

Website: http://localhost:80

Youtube: http://localhost:80

Chúc các bạn thành công!

Các lần chỉnh sửa


Written by admin


Comments

This post currently has no responses.

Leave a Reply