제이온

[Effective Java] Mục 3: Đảm bảo Singleton bằng Constructor Riêng Tư hoặc Kiểu Liệt kê

  • Ngôn ngữ viết: Tiếng Hàn Quốc
  • Quốc gia: Tất cả các quốc giacountry-flag
  • CNTT

Đã viết: 2024-04-27

Đã viết: 2024-04-27 00:48

Singleton

Khái niệm Singleton

Singleton là một lớp mà chỉ có thể tạo ra duy nhất một instance. Ví dụ điển hình về Singleton là các đối tượng không trạng thái hoặc các thành phần hệ thống duy nhất. Tuy nhiên, các lớp Singleton lại gặp vấn đề khó khăn trong việc kiểm thử nếu chúng không được định nghĩa bằng giao diện và triển khai của nó thay vì định nghĩa trực tiếp bằng lớp.


Cách tạo Singleton

Phương thức sử dụng thành viên static public là trường final



Constructor private chỉ được gọi một lần khi khởi tạo instance Elvis và đảm bảo rằng nó là instance duy nhất trong toàn bộ hệ thống. Tuy nhiên, có thể gọi constructor private bằng cách sử dụng AccessibleObject.setAccessible(), phương thức Reflection này có thể được ngăn chặn bằng cách ném exception khi tạo instance thứ 2.


  • Ưu điểm
    • API rõ ràng cho thấy lớp này là Singleton.
    • Ngắn gọn.


Phương thức cung cấp phương thức factory static public


Ngoài việc sử dụng Reflection để thay đổi, phương thức này cũng đảm bảo rằng nó là instance duy nhất trong toàn bộ hệ thống. Chỉ đơn giản là thay đổi trường thành private và sử dụng phương thức factory static để trả về đối tượng.


  • Ưu điểm
    • Có thể thay đổi thành không phải Singleton mà không cần thay đổi API.
      • Ví dụ: phương thức factory static có thể trả về các instance khác nhau cho mỗi luồng.
    • Có thể thay đổi thành phương thức factory Singleton Generics nếu muốn.
    • Tham chiếu phương thức của factory static có thể được sử dụng làm supplier.
      • Ví dụ: có thể sử dụng Elvis::getInstance thay vì Supplier<Elvis>.


Nếu không cần sử dụng các ưu điểm trên, thì nên sử dụng phương thức đầu tiên.


Phương thức sử dụng enum


Phương thức tốt nhất là sử dụng enum. So với hai phương thức trên, nó an toàn hơn với các cuộc tấn công Reflection và mã cũng gọn gàng hơn. Ngoài ra, như sẽ được mô tả ở bên dưới, hai phương thức trên có nhược điểm là phải thêm mã bổ sung khi serialize.

Tuy nhiên, cần lưu ý rằng Singleton được tạo ra có thể kế thừa giao diện nhưng không thể kế thừa lớp.


Những điểm cần lưu ý khi serialize lớp Singleton

Nếu muốn serialize lớp Singleton được tạo bằng phương thức đầu tiên hoặc thứ hai, ngoài việc triển khai Serializable, bạn cần phải khai báo tất cả các trường instance là transient và ghi đè phương thức readResolve().



Nguồn tham khảo

Bình luận0