Làm thế nào để bạn xác định một lớp hằng số trong Java?


89

Giả sử bạn cần xác định một lớp mà tất cả những gì nó làm là giữ các hằng số.

public static final String SOME_CONST = "SOME_VALUE";

Cách ưa thích để làm điều này là gì?

  1. Giao diện
  2. Lớp trừu tượng
  3. Lớp cuối cùng

Tôi nên sử dụng cái nào và tại sao?


Làm rõ một số câu trả lời:

Enums - Tôi sẽ không sử dụng enums, tôi không liệt kê bất cứ thứ gì, chỉ thu thập một số hằng số không liên quan đến nhau theo bất kỳ cách nào.

Giao diện - Tôi sẽ không đặt bất kỳ lớp nào làm lớp triển khai giao diện. Chỉ muốn sử dụng giao diện để gọi hằng số như sau: ISomeInterface.SOME_CONST.


Có một số cuộc thảo luận tương tự ở đây: stackoverflow.com/questions/320588/… . Tôi sẽ sử dụng một lớp cuối cùng với một phương thức khởi tạo riêng để nó không thể được khởi tạo.
Dan Dyer

2
Xin lỗi nhưng "Tôi sẽ không sử dụng enums" biến câu hỏi này thành "cách tốt nhất để làm điều gì đó ngu ngốc là gì?"
cletus

Tôi không nói rằng bạn sẽ triển khai giao diện. Nhưng không có ích gì khi sử dụng một giao diện để làm điều đó. Vì vậy, hãy đi với lớp học cuối cùng:)
Megacan

Có vấn đề gì với Enum? Bạn luôn có thể sử dụng nó để thu thập 'một số hằng số không liên quan đến nhau theo bất kỳ cách nào'. Hmm?
gedevan

5
Về mặt khái niệm, một enum là một lựa chọn tồi nếu các hằng số không liên quan. Một enum đại diện cho các giá trị thay thế cùng loại. Những hằng số không thay thế và họ thậm chí có thể không cùng loại (một số có thể chuỗi, số nguyên, vv)
Dan Dyer

Câu trả lời:


92

Sử dụng một lớp cuối cùng. để đơn giản hơn, bạn có thể sử dụng nhập tĩnh để sử dụng lại các giá trị của mình trong một lớp khác

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

trong một lớp khác:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}

4
Lợi ích của việc tạo một lớp riêng ở đây là ở đâu? Mặc dù tôi thường không coi API Lịch như một ví dụ điển hình về thiết kế, nhưng về mặt "các hằng số liên quan đến lịch đều nằm trong lớp Lịch".
Jon Skeet

7
lợi ích là không trùng lặp mã, trong trường hợp bạn cần sử dụng lại các hằng số trong nhiều hơn một lớp. Tôi đoán bạn có thể dễ dàng nhìn thấy lợi thế của điều này.
user54579

2
Tại sao bạn sẽ sao chép mã? Chỉ cần tham khảo các lớp khác. Tôi thấy tương đối hiếm khi một hằng số thực sự đứng một mình.
Jon Skeet

14
Để dễ đọc hơn, tôi cũng sẽ có một hàm tạo mặc định riêng không có nội dung (và một nhận xét phù hợp).
Ran Biron

5
Câu trả lời khá cũ, và nhận xét này có lẽ không đúng chỗ, nhưng tôi sẽ sử dụng VALUE1.equals(variable)vì nó tránh NPE.
Aakash

38

Việc làm rõ của bạn nêu rõ: "Tôi sẽ không sử dụng enums, tôi không liệt kê bất cứ thứ gì, chỉ thu thập một số hằng số không liên quan đến nhau theo bất kỳ cách nào."

Nếu các hằng số hoàn toàn không liên quan đến nhau, tại sao bạn lại muốn thu thập chúng cùng nhau? Đặt mỗi hằng số vào lớp mà nó có liên quan chặt chẽ nhất.


2
Jon - chúng có liên quan với nhau theo nghĩa là chúng đều thuộc cùng một chức năng. Tuy nhiên, chúng không phải là một bảng kê của bất cứ thứ gì ... Chúng không nắm giữ tài sản mà một đối tượng là "một trong những thứ đó".
Yuval Adam

13
Được chứ. Trong trường hợp đó, chỉ cần đặt chúng vào lớp gần nhất với chức năng mà chúng liên quan đến.
Jon Skeet

26

Đề xuất của tôi (theo thứ tự ưu tiên giảm dần):

1) Đừng làm điều đó . Tạo các hằng số trong lớp thực tế mà chúng có liên quan nhất. Việc có một lớp / giao diện 'túi hằng số' không thực sự tuân theo các phương pháp hay nhất của OO.

Tôi và tất cả những người khác, thỉnh thoảng bỏ qua # 1. Nếu bạn định làm điều đó thì:

2) lớp cuối cùng với phương thức khởi tạo riêng Điều này ít nhất sẽ ngăn bất kỳ ai lạm dụng 'túi hằng số' của bạn bằng cách mở rộng / triển khai nó để dễ dàng truy cập vào các hằng số. (Tôi biết bạn đã nói rằng bạn sẽ không làm điều này - nhưng điều đó không có nghĩa là ai đó sẽ đi cùng sau khi bạn không làm thế)

3) giao diện Điều này sẽ hoạt động, nhưng không phải sở thích của tôi đưa ra đề cập lạm dụng có thể xảy ra trong # 2.

Nói chung, chỉ vì đây là các hằng số không có nghĩa là bạn vẫn không nên áp dụng các nguyên tắc bình thường cho chúng. Nếu không có ai ngoại trừ một lớp quan tâm đến một hằng số - thì nó phải là hằng số và nằm trong lớp đó. Nếu chỉ các bài kiểm tra quan tâm đến một hằng số - thì nó phải nằm trong một lớp kiểm tra, không phải mã sản xuất. Nếu một hằng số được xác định ở nhiều nơi (không chỉ vô tình giống nhau) - hãy cấu trúc lại để loại bỏ sự trùng lặp. Và cứ thế - hãy đối xử với họ như cách bạn làm.


2
Vấn đề của 1 là đôi khi bạn sẽ đưa vào mã của mình một số phụ thuộc vào một lớp cấp khác chỉ để tìm nạp hằng số.
amdev

Tất cả các lĩnh vực trong một giao diện đang ngầm công cộng, tĩnh và cuối cùng
Kodebetter

@Kodebetter Nhưng các giao diện có thể được mở rộng / triển khai để thêm nhiều trường hơn.
Chứng kiến

12

Như Joshua Bloch ghi chú trong Java hiệu quả:

  • Các giao diện chỉ nên được sử dụng để xác định các loại,
  • các lớp trừu tượng không ngăn cản tính ổn định (chúng có thể được phân lớp con và thậm chí gợi ý rằng chúng được thiết kế để được phân lớp).

Bạn có thể sử dụng Enum nếu tất cả các hằng số của bạn có liên quan (như tên hành tinh), đặt các giá trị hằng số trong các lớp mà chúng có liên quan đến (nếu bạn có quyền truy cập vào chúng) hoặc sử dụng một lớp tiện ích không thể cài đặt được (xác định một hàm tạo mặc định riêng) .

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

Sau đó, như đã nêu, bạn có thể sử dụng nhập tĩnh để sử dụng các hằng số của mình.


7

Phương pháp ưa thích của tôi là hoàn toàn không làm điều đó. Thời đại của các hằng số đã chết đi khá nhiều khi Java 5 giới thiệu các enums an toàn kiểu loại. Và thậm chí trước đó Josh Bloch đã xuất bản một phiên bản (dài dòng hơn một chút) của phiên bản đó, hoạt động trên Java 1.4 (và trước đó).

Trừ khi bạn cần khả năng tương tác với một số mã kế thừa thì thực sự không có lý do gì để sử dụng các hằng số String / integer được đặt tên nữa.


2
Câu trả lời tốt, một ví dụ sẽ tốt hơn.
amdev

3

Chỉ cần sử dụng lớp cuối cùng.

Nếu bạn muốn có thể thêm các giá trị khác, hãy sử dụng một lớp trừu tượng.

Sẽ không có ý nghĩa gì khi sử dụng một giao diện, một giao diện được cho là chỉ định một hợp đồng. Bạn chỉ muốn khai báo một số giá trị không đổi.



3

enums ổn. IIRC, một mục trong Java hiệu quả (Phiên bản thứ 2) có các enumhằng số liệt kê các tùy chọn tiêu chuẩn triển khai [từ khóa Java]interface cho bất kỳ giá trị nào.

Sở thích của tôi là sử dụng [từ khóa Java] interfacetrên a final classcho hằng số. Bạn mặc nhiên nhận được public static final. Một số người sẽ tranh luận rằng an interfacecho phép những lập trình viên tồi thực hiện nó, nhưng những lập trình viên tồi sẽ viết những đoạn mã tệ hại bất kể bạn làm gì.

Cái nào trông đẹp hơn?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

Hoặc là:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}

nhưng những lập trình viên tồi sẽ viết những đoạn mã tệ hại cho dù bạn làm gì đi nữa. Điều đó chỉ đúng như vậy. Nếu bạn có thể thực hiện các bước để giảm thiểu lập trình xấu hoặc loại bỏ hoàn toàn nó, thì bạn có một chút trách nhiệm phải làm điều đó; càng rõ ràng càng tốt. Một lập trình viên tồi không thể mở rộng lớp cuối cùng.
liltitus27

1
@ liltitus27 Tôi đồng ý ở một mức độ nào đó. Nhưng bạn có thực sự muốn mã không xác minh chỉ để ngăn chặn một cách lập trình viên kém viết mã xấu? Mã do họ tạo ra sẽ vẫn vô vọng, nhưng bây giờ mã của bạn khó đọc hơn.
Tom Hawtin - tackline

1

Hoặc 4. Đặt chúng vào lớp chứa logic sử dụng hằng số nhiều nhất

... xin lỗi, không thể cưỡng lại ;-)


3
Đây không phải là ý tưởng tốt. Điều này tạo ra sự phụ thuộc giữa các lớp mà không nên có.
Yuval Adam

Tại sao không? Tôi muốn nói rằng các lớp sử dụng các hằng số giống nhau dù sao cũng có sự phụ thuộc ... Và bằng cách nào đó phải có một lớp phụ thuộc nhiều nhất vào các hằng số này.
Simon Groenewolt

Nếu chỉ có một lớp sử dụng hằng số, điều này có thể có ý nghĩa.
Tom Hawtin - tackline vào

-1
  1. Một trong những nhược điểm của phương thức khởi tạo riêng là sự tồn tại của phương thức không bao giờ có thể được kiểm tra.

  2. Enum theo khái niệm bản chất tốt để áp dụng trong loại miền cụ thể, áp dụng nó cho các hằng số phi tập trung có vẻ không đủ tốt

Khái niệm Enum là "Enumerations là tập hợp các mục có liên quan chặt chẽ với nhau".

  1. Mở rộng / triển khai một giao diện không đổi là một thực tế không tốt, thật khó để nghĩ đến yêu cầu mở rộng một hằng số bất biến thay vì đề cập trực tiếp đến nó.

  2. Nếu áp dụng công cụ chất lượng như SonarSource, có những quy tắc buộc nhà phát triển phải bỏ giao diện liên tục, đây là một điều khó xử vì rất nhiều dự án thích giao diện không đổi và hiếm khi thấy những thứ "mở rộng" xảy ra trên giao diện không đổi


1
"private constructor là sự tồn tại của phương thức không bao giờ có thể được kiểm tra": không đúng. Nếu bạn (hoặc sếp của bạn) thực sự hoang tưởng về việc báo cáo độ phủ mã là 100%, bạn vẫn có thể kiểm tra điều này bằng cách sử dụng phản xạ và đảm bảo hàm tạo ném ra một ngoại lệ. Nhưng, IMHO, đây chỉ là hình thức và không thực sự cần phải thử nghiệm. Nếu bạn (hoặc nhóm) chỉ thực sự quan tâm đến những gì thực sự quan trọng, thì độ phủ 100% đường truyền là không cần thiết.
L. Holanda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.