Gần đây, bạn đã tìm hiểu sâu về mẫu thiết kế singleton , cách triển khai nó trong Java và nó dùng để làm gì. Nhưng nếu tôi nói với bạn rằng Java đi kèm với một singleton riêng của nó thì sao? Có mưu đồ? Sau đó, hãy đi sâu vào.

Có thể bạn đã biết về lớp Enum . Nó có một tính năng đặc biệt mà bạn nên biết. Cụ thể, Enum triển khai mẫu thiết kế singleton. Tùy chọn này gần giống như cách tiếp cận đơn lẻ liên quan đến trường công khai .

Độc thân như enum:


public enum Device {   
    PRINTER	
} 
    

Singleton như một biến công khai:


public class Printer {   
    public static final Printer PRINTER = new Printer();   
    private Printer() {
    }
//…
}
    

Cách tiếp cận enum nhỏ gọn hơn cách tiếp cận trường công cộng, vì chúng ta không cần phải viết triển khai của riêng mình. Quan trọng nhất, enums không có vấn đề gì với việc tuần tự hóa.

Việc tuần tự hóa các enum hoạt động khác với các đối tượng thông thường: chỉ giá trị của tên enum được tuần tự hóa. Trong quá trình giải tuần tự hóa, phương thức này được sử dụng với tên đã giải tuần tự hóa để lấy một thể hiện. Ngoài ra, enum có thể bảo vệ bạn chống lại các cuộc tấn công phản chiếu .

Bạn sẽ tìm hiểu thêm về phản ánh trong các bài học trong mô-đun thứ hai, nơi chúng ta sẽ khám phá API phản chiếu .

Java cấm khởi tạo enums — một giới hạn được đưa vào việc triển khai phương thức newInstance của lớp Constructor , phương thức này thường được gọi khi tạo các đối tượng thông qua sự phản chiếu.

Đoạn trích mã từ Constructor.newInstance . Được sử dụng để tạo một enum :


if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
    

Nhược điểm của việc sử dụng enum để tạo singleton bao gồm:

  • Thiếu khởi tạo lười biếng, vì đối tượng được tạo ngay lập tức và việc khởi tạo không thể bị trì hoãn.

  • Các lớp khác không được gia hạn. Nghĩa là, trong trường hợp bạn cần kế thừa một lớp khác, thì việc sử dụng enum làm đơn lẻ sẽ không hiệu quả. Trong những trường hợp như vậy, chúng ta cần chuyển sang các tùy chọn triển khai khác đã quen thuộc với chúng ta: phương thức tĩnh hoặc biến công khai.

  • Khi sử dụng enum làm đơn lẻ, bạn chỉ có thể sử dụng một trường enum .


public enum Device extends Electricity { 
    PRINTER 
}
    

Mã này sẽ cho chúng tôi một lỗi biên dịch:

Không có mệnh đề mở rộng nào được phép cho enum

Nhưng nếu chúng ta cần triển khai một giao diện thì không có vấn đề gì, vì enum có thể triển khai các giao diện:


public enum Device implements Electricity { 
    PRINTER 
}
    

Nếu bạn không cần sử dụng tính kế thừa, tốt nhất là triển khai mẫu đơn thông qua enum . Chúng tôi không đơn độc đề xuất điều này — chính Joshua Bloch cũng vậy .

Cách tiếp cận triển khai này mang đến cho bạn sự tiện lợi, nhỏ gọn, tuần tự hóa ngay lập tức, bảo vệ khỏi các cuộc tấn công phản chiếu và tính duy nhất — mọi thứ mà một người độc thân giỏi cần có!