Design Pattern series: Giới thiệu Singleton

Bài viết được sự cho phép của tác giả Phạm Minh Khoa

Singleton là gì? Singleton là 1 trong 5 design pattern của nhóm khởi tạo (Creational Design Pattern). Vậy cấu trúc của Singleton ra sao và cách triển khai như thế nào, cùng mình tìm hiểu nội dung dưới đây.

Định nghĩa

Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.

Dịch: Singleton là 1 mẫu design pattern thuộc nhóm khởi tạo cho phép bạn đảm bảo rằng 1 lớp sẽ chỉ có duy nhất 1 instance và nó cung cấp 1 method cho instance này ở bất cứ đâu trong chương trình.

Singleton giải quyết bài toán nào?

Singleton Pattern giải quyết 2 vấn đề dưới đây cùng 1 lúc:

  • Đảm bảo rằng 1 lớp (class) sẽ chỉ có 1 instance duy nhất: Sẽ có 1 số trường hợp mà bạn cần kiểm soát việc truy cập đến các tài nguyên dùng chung ví dụ như database hay 1 file nào đó; lúc này bạn cần kiểm soát được số lượng instance mà 1 class đó có.

Cách nó hoạt động sẽ như sau: Thử tưởng tượng rằng bạn đã tạo 1 object rồi, tuy nhiên sau đó bạn lại quyết định tạo thêm 1 object mới. Lúc này thay vì việc nhận được 1 object mới thì bạn sẽ nhận về object mà bạn tạo ra lúc trước.

Lưu ý rằng hành vi này không thể thực hiện với 1 phương thức khởi tạo thông thường (như sử dụng new), vì nó sẽ luôn trả về 1 object mới.

Ở đây khách hàng có thể không nhận ra rằng họ đang làm việc với cùng 1 đối tượng
  • Cung cấp 1 điểm truy cập global đến instance đó: Biến global (toàn cục) thường được sử dụng để lưu trữ 1 số đối tượng thiết yếu. Mặc dù nó rất là tiện dụng, nhưng chúng cũng rất không an toàn vì bất cứ đoạn code nào trong chương trình cũng có thể ghi đè nội dung của những biến đó khiến cho ứng dụng của chúng ta bị crash. Singleton cũng giống như biến toàn cục, nó cho phép bạn truy cập đến 1 số object ở bất kỳ đâu trong chương trình, tuy nhiên nó cũng bảo vệ instance đó tránh khỏi việc bị ghi đè bởi code khác.

Có 1 cách nhìn khác cho vấn đề này: bạn không muốn phần code giải quyết vấn đề #1 ở trên bị phân tán khắp nơi trong chương trình, source code của mình. Sẽ tốt hơn khi chúng được viết hết trong 1 class đặc biệt là nếu các phần code khác đã phụ thuộc vào nó.

Cách triển khai Singleton

Tất cả các triển khai (implementations) của Singleton đều sẽ gồm 2 bước chung sau:

  • Đặt phương thức khởi tạo mặc định (default constructor) là private để ngăn việc các đối tượng khác sử dụng toán tử new cho lớp Singleton
  • Tạo 1 phương thức khởi tạo static hoạt động như 1 khởi tạo (constructor), trong đó phương thức này sẽ gọi private constructor để tạo ra 1 object và lưu nó vào trường static (static field). Tất cả các lệnh gọi sau đến phương thức này đều trả về đối tượng được lưu trong cached.

Nếu code của bạn truy cập đến lớp Singleton, nó có thể gọi đến phương thức static của Singleton, và sẽ luôn luôn được trả về chung 1 object.

Ví dụ thực tế

Singleton có nhiều ví dụ thực tế:

  • 1 đất nước có thể chỉ có 1 chính phủ chính thức. Bất kể ai, cá nhân nào làm việc cho chính phủ thì danh xưng “Chính phủ” vẫn là 1 khái niệm chỉ định chung dùng để chỉ nhóm những người phụ trách. Chính phủ ở đây được xem như 1 ví dụ về Singleton.
  • Khi bạn muốn tăng giảm âm lượng của 1 chiếc điện thoại. Bất kể có gọi từ phần mềm thứ 3, hay thao tác trực tiếp trên phần cứng; thì việc tăng giảm âm lượng cũng đều được thực hiện thông qua 1 phần điều khiển hệ thống. Ta cũng xem lớp điều khiển âm lượng này là 1 singleton
  • Máy in cũng có thể xem là 1 singleton khi nó nhận yêu cầu và xử lý từ mọi người trong hệ thống.

Cấu trúc, cách triển khai Singleton

Lớp Singleton khai báo phương thức static getInstance trả về cùng 1 instance của nó.

Phương thức khởi tạo Singleton nên được ẩn khỏi code client, cách duy nhất để lấy đối tượng Singleton là gọi phương thức getInstance.

Triển khai Singleton Pattern code với TypeScript

/**
 * The Singleton class defines the `getInstance` method that lets clients access
 * the unique singleton instance.
 */
class Singleton {
    private static instance: Singleton;

    /**
     * The Singleton's constructor should always be private to prevent direct
     * construction calls with the `new` operator.
     */
    private constructor() { }

    /**
     * The static method that controls the access to the singleton instance.
     *
     * This implementation let you subclass the Singleton class while keeping
     * just one instance of each subclass around.
     */
    public static getInstance(): Singleton {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }

        return Singleton.instance;
    }

    /**
     * Finally, any singleton should define some business logic, which can be
     * executed on its instance.
     */
    public someBusinessLogic() {
        // ...
    }
}

/**
 * The client code.
 */
function clientCode() {
    const s1 = Singleton.getInstance();
    const s2 = Singleton.getInstance();

    if (s1 === s2) {
        console.log('Singleton works, both variables contain the same instance.');
    } else {
        console.log('Singleton failed, variables contain different instances.');
    }
}

clientCode();
Nội dung trên đã phần nào giải đáp được thắc mắc Singleton là gì cũng như những ứng dụng thực tế của Singleton. Nếu bạn muốn góp ý đừng ngần ngại phản hồi với TopDev nhé. Chúc bạn code mau lên trình.
Bài viết gốc được đăng tải tại anywayblogs.com
Related post:

Đừng bỏ qua việc làm IT tất cả level có trên TopDev nhé!