Backend

99 Ngày Java — Ngày 92: Singleton và Factory

SSite Admin
27 tháng 10, 2026 3 phút đọc 6 lượt xem
99 Ngày Java — Ngày 92: Singleton và Factory

Các mẫu khởi tạo trả lời câu hỏi ai tạo đối tượng và tạo thế nào. Singleton bảo đảm chỉ có một instance; các mẫu Factory giấu việc chọn lớp cụ thể sau một phương thức. Cả hai rất phổ biến, và cả hai đều dễ bị lạm dụng, nên bài này nói cả cách viết đúng lẫn lúc không nên dùng.

Singleton và Factory

1. Singleton thread-safe

Cách đơn giản nhất là khởi tạo sớm trong một trường static final: JVM bảo đảm việc khởi tạo lớp là thread-safe. Nếu cần khởi tạo trễ, dùng holder idiom: instance nằm trong một lớp lồng static và chỉ được tạo khi lớp đó được nạp lần đầu. Double-checked locking cũng đúng nhưng bắt buộc trường phải là volatile và dễ viết sai, nên hiếm khi đáng dùng.

final class AppClock {
    private AppClock() {}

    private static final class Holder {
        static final AppClock INSTANCE = new AppClock();
    }

    static AppClock instance() { return Holder.INSTANCE; } // lazy, thread-safe
}

2. Enum singleton và mặt trái của singleton

Enum một phần tử là singleton gọn nhất: JVM bảo đảm chỉ có một instance, kể cả khi deserialize hay bị tấn công bằng reflection. Nhưng mọi singleton đều là trạng thái toàn cục: lớp dùng nó giấu phụ thuộc bên trong, test khó thay thế và các test ảnh hưởng lẫn nhau. Trong ứng dụng có dependency injection, hãy để container giữ một instance và truyền nó qua constructor.

enum IdGenerator {
    INSTANCE;

    private final AtomicLong next = new AtomicLong(1);
    long nextId() { return next.getAndIncrement(); }
}

long id = IdGenerator.INSTANCE.nextId();

3. Static factory và Factory Method

Static factory method là phương thức tĩnh trả về instance, ví dụ List.of hay Optional.empty. So với constructor, nó có tên, có thể trả về kiểu con và có thể tái sử dụng instance. Mẫu Factory Method đi xa hơn một bước: lớp cha định nghĩa quy trình và gọi một phương thức trừu tượng để tạo đối tượng, lớp con quyết định tạo loại nào.

sealed interface Notifier permits EmailNotifier, SmsNotifier {
    void send(String to, String message);

    static Notifier of(Channel channel) {          // static factory
        return switch (channel) {
            case EMAIL -> new EmailNotifier();
            case SMS -> new SmsNotifier();
        };
    }
}

4. Abstract Factory: tạo cả một họ đối tượng

Abstract Factory là một interface có nhiều phương thức tạo, mỗi cài đặt cho ra một bộ đối tượng ăn khớp với nhau. Ví dụ một factory cho AWS tạo storage và queue của AWS, factory cho môi trường local tạo bản chạy trong bộ nhớ. Code nghiệp vụ chỉ biết interface, nên đổi cả họ chỉ cần đổi một factory và không thể vô tình trộn hai họ.

  • Bắt đầu bằng constructor; thêm factory khi việc chọn lớp cụ thể trở nên phức tạp hoặc lặp lại.

  • Factory là nơi duy nhất biết các lớp cụ thể.

  • Trong Spring, container chính là factory: @Bean là factory method.

interface CloudFactory {
    BlobStorage storage();
    MessageQueue queue();
}

final class LocalFactory implements CloudFactory {
    public BlobStorage storage() { return new InMemoryStorage(); }
    public MessageQueue queue() { return new InMemoryQueue(); }
}

Singleton giới hạn số instance, factory giới hạn chỗ biết lớp cụ thể. Ngày 93 xem hai mẫu khởi tạo còn lại: Builder và Prototype.

Tài liệu đối chiếu

  • https://refactoring.guru/design-patterns/singleton

  • https://refactoring.guru/design-patterns/abstract-factory

S

Site Admin

Engineer and writer. Building things with TypeScript and distributed systems.

Bình luận (0)

Bạn cần đăng nhập bằng Google để bình luận.

Hãy là người bình luận đầu tiên.

Bài viết liên quan

99 Ngày Spring — Ngày 92: Structured Logging

Log dạng JSON, MDC và correlation id, key-value thay cho ghép chuỗi, và cách tập trung log từ nhiều instance.

27 thg 10, 20262 phút4
99 Ngày Java — Ngày 91: SOLID

Năm nguyên tắc thiết kế hướng đối tượng kèm ví dụ Java, và cách nhận ra code smell báo hiệu chúng bị vi phạm.

26 thg 10, 20263 phút7
99 Ngày Spring — Ngày 91: Config và Secrets cho Production

Cấu hình theo 12-factor, thứ tự ưu tiên của property, @ConfigurationProperties có kiểm tra và cách quản lý secret an toàn.

26 thg 10, 20263 phút5