Tôi thấy hầu hết các POJO bất biến được viết như thế này:
public class MyObject {
private final String foo;
private final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
public String getFoo() {
return foo;
}
public int getBar() {
return bar;
}
}
Tuy nhiên, tôi có xu hướng viết chúng như thế này:
public class MyObject {
public final String foo;
public final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
}
Lưu ý các tài liệu tham khảo là cuối cùng, vì vậy Đối tượng vẫn không thay đổi. Nó cho phép tôi viết ít mã hơn và cho phép truy cập ngắn hơn (bằng 5 ký tự: getvà ()).
Nhược điểm duy nhất tôi có thể thấy là nếu bạn muốn thay đổi việc thực hiện getFoo()xuống đường để làm điều gì đó điên rồ, bạn không thể. Nhưng thực tế, điều này không bao giờ xảy ra vì Đối tượng là bất biến; bạn có thể xác minh trong instantiation, tạo bản sao phòng thủ không thể thay đổi trong instantiation (xem ổi của ImmutableListví dụ), và nhận được foohoặc barcác đối tượng sẵn sàng cho các getcuộc gọi.
Có bất kỳ nhược điểm nào tôi đang thiếu?
BIÊN TẬP
Tôi cho rằng một nhược điểm khác mà tôi thiếu là các thư viện tuần tự hóa sử dụng sự phản chiếu qua các phương thức bắt đầu bằng gethoặc is, nhưng đó là một thực tế khá khủng khiếp ...
String, inthoặc MyObject. Trong phiên bản đầu tiên, finalchỉ để đảm bảo rằng các phương thức khác ngoài hàm tạo trong lớp không cố gắng bar = 7;, chẳng hạn. Trong phiên bản thứ hai, finalcần thiết để ngăn người tiêu dùng thực hiện : MyObject x = new MyObject("hi", 5); x.bar = 7;.
Objectvẫn không thay đổi. " Là sai lệch - theo cách mà nó xuất hiện mà bạn nghĩ rằng bất kỳ final Objectlà bất biến, điều đó không phải là bất biến. Xin lỗi vì sự hiểu lầm.
myObj.getFoo().setFrob(...).
finalkhông biến một đối tượng thành bất biến. Tôi thường sử dụng một thiết kế trong đó tôi xác địnhfinalcác trường trước khi tạo cuộc gọi lại để gọi lại có thể truy cập vào các trường đó. Tất nhiên nó có thể gọi tất cả các phương thức bao gồm mọisetXphương thức.