Design Patterns - Singleton pattern

Mẫu thiết kế Singleton đảm bảo rằng một lớp chỉ có một thể hiện (instance) duy nhất. Do thể hiện này có tiềm năng sử dụng trong suốt chương trình, nên mẫu thiết kế Singleton cũng cung cấp một điểm truy cập toàn cục đến nó.

Cài đặt

singleton_pattern_uml_diagram.jpg

Mẫu thiết kế Singleton đơn giản và dễ áp dụng, chỉ cần bổ sung vài dòng lệnh trong lớp muốn chuyển thành Singleton.

  • Dữ liệu thành viên instance (private và static) là đối tượng duy nhất của lớp Singleton.

  • Constructor của lớp Singleton được định nghĩa thành protected hoặc private để người dùng không thể tạo thực thể trực tiếp từ bên ngoài lớp.

  • Phương thức getInstance() dùng để khởi tạo đối tượng duy nhất, định nghĩa thành public và static. Client chỉ dùng getInstance() để tạo đối tượng cho lớp Singleton.

  • Thực hiện khởi tạo chậm (lazy initialization) trong getInstance(): chỉ khi gọi phương thức getInstance() mới khởi tạo đối tượng. Phương thức này trả về một thể hiện mới hay null tùy thuộc vào một tham số kiểu boolean dùng như cờ hiệu bào xem lớp Singleton đã tạo thể hiện hay chưa.

Trong chế độ multithreading, mẫu thiết kế Singleton có thể làm việc không tốt: do getInstance() không an toàn thread, hai thread có thể gọi phương thức sinh đối tượng cùng một thời điểm và hai thể hiện sẽ được tạo ra. Nếu đồng bộ (synchronized) phương thức getInstance() để an toàn thread sẽ dẫn đến giảm hiệu suất chương trình.

Dưới đây là ví dụ về cách tạo ra 1 singleton:

package com.excample.designpattern.singleton;

class Singleton {

    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class ClassSingleton {

    public static void main(String[] args) {
        System.out.println("--- Singleton Pattern ---");
        Singleton single1 = Singleton.getInstance();
        Singleton single2 = Singleton.getInstance();
        if (single1.equals(single2)) {
            System.out.println("Unique Instance");
        }
    }
}

Liên quan

  • Abstract Factory: thường là Singleton để trả về các đối tượng factory duy nhất.

  • Builder: dùng để xây dựng một đối tượng phức tạp, trong đó Singleton được dùng để tạo một đối tượng truy cập tổng quát (Director).

  • Prototype: dùng để sao chép một đối tượng, hoặc tạo ra một đối tượng khác từ Prototype của nó, trong đó Singleton được dùng để chắc chắn chỉ có một Prototype.

Java API

  • Lớp java.lang.Runtime là lớp Singleton, để lấy được đối tượng duy nhất của nó, ta gọi phương thức getRuntime(). Tương tự, lớp java.awt.Desktop cũng là lớp Singleton, tạo đối tượng duy nhất bằng phương thức getDesktop(). Singleton không phổ biến như ta nghỉ, nó chỉ áp dụng với lớp cần bảo đảm chỉ có một thể hiện duy nhất.

Các trường hợp nên dùng

  • Đảm bảo rằng chỉ có một thể hiện của lớp.
  • Quản lý việc truy cập tốt hơn vì chỉ có một thể hiện duy nhất.
  • Quản lý số lượng thể hiện của một lớp. Trường hợp này không nhất thiết chỉ có một thể hiện, bạn cần kiểm soát số lượng thể hiện trong giớn hạn chỉ định.