2013-06-09 35 views
39

Giả sử tôi có một enum:Cách tốt nhất để triển khai `next` và` previous` trên một kiểu enum là gì?

enum E { 
    A, B, C; 
} 

Như đã trình bày trong this answer bởi lucasmo, các giá trị enum được lưu trữ trong một mảng tĩnh theo thứ tự mà chúng được khởi tạo, và sau đó bạn có thể lấy (một bản sao của) mảng này với E.values().

Bây giờ giả sử tôi muốn thực hiện E#getNextE#getPrevious như rằng tất cả các từ ngữ dưới đây đánh giá để true:

E.A.getNext() == E.B 
E.B.getNext() == E.C 
E.C.getNext() == E.A 

E.A.getPrevious() == E.C 
E.B.getPrevious() == E.A 
E.C.getPrevious() == E.B 

thực hiện hiện tại của tôi cho getNext như sau:

public E getNext() { 
    E[] e = E.values(); 
    int i = 0; 
    for (; e[i] != this; i++) 
     ; 
    i++; 
    i %= e.length; 
    return e[i]; 
} 

và một tương tự phương thức cho getPrevious.

Tuy nhiên, mã này có vẻ rườm rà lúc tốt nhất (ví dụ, "trống rỗng" for vòng lặp, lạm dụng gây tranh cãi của một biến đếm, và có khả năng sai lầm lúc tồi tệ nhất (nghĩ suy, có thể).

Điều gì sẽ là cách tốt nhất để thực hiện getNextgetPrevious phương pháp với nhiều loại enum trong Java 7


LƯU ý: tôi làm không có ý định câu hỏi này là chủ quan theo yêu cầu của tôi cho implementa "tốt nhất". tion là viết tắt của yêu cầu cho việc thực hiện đó là nhanh nhất, sạch nhất, và duy trì nhất.

+0

'E.C.getPrevious() == E.C' hoặc' E.C.getPrevious() == E.B'? – johnchen902

+0

@ johnchen902 đã được sửa; xin lỗi – wchargin

Trả lời

58

Hãy thử điều này:

public static enum A { 
    X, Y, Z; 
    private static A[] vals = values(); 
    public A next() 
    { 
     return vals[(this.ordinal()+1) % vals.length]; 
    } 

Thực hiện previous() là trái như một bài tập, nhưng nhớ lại rằng in Java, the modulo a % b can return a negative number.

EDIT: Như được đề xuất, tạo bản sao tĩnh riêng tư của mảng values() để tránh sao chép mảng mỗi lần next() hoặc previous() được gọi.

+1

Ah! Tôi không biết về 'thứ tự'; Tôi đã tìm 'indexOf'. Sẽ tốt hơn nếu khai báo 'A [] values ​​= values ​​()' để tránh nhân bản hai lần? – wchargin

+0

Tôi sẽ ngạc nhiên nếu có bất kỳ nhân bản nào có liên quan vì giá trị enum là những người độc thân. Bạn luôn có thể xem mã được tạo. –

+1

Phương thức 'values' trả về' (A []) ($ VALUES.clone()) 'trong đó' private static final A [] $ VALUES = new A [] {X, Y, Z} '. Xem [câu trả lời này] (http://stackoverflow.com/a/1163121/732016). – wchargin

4

Ngoài ra, người ta có thể đi bằng cách nào đó dọc theo dòng của ý tưởng sau đây:

public enum SomeEnum { 
    A, B, C; 

    public Optional<SomeEnum> next() { 
    switch (this) { 
     case A: return Optional.of(B); 
     case B: return Optional.of(C); 
     // any other case can NOT be mapped! 
     default: return Optional.empty(); 
    } 
} 

Ghi chú:

  1. Ngược lại với câu trả lời khác, cách này hiện một số ngầm mapping; thay vì dựa vào ordinal(). Tất nhiên điều đó có nghĩa là nhiều mã hơn; nhưng nó cũng buộc tác giả phải xem xét ý nghĩa của việc thêm các hằng số mới hoặc xóa các hằng số hiện tại. Khi dựa vào thứ tự, giả định ngụ ý tiềm ẩn của bạn là đơn đặt hàng được dựa trên thứ tự được sử dụng cho khai báo hằng số enum. Vì vậy, khi ai đó trở lại 6 tháng sau đó và phải thêm một hằng số mới, anh ta phải hiểu rằng hằng số Y mới cần X, Y, Z ... thay vì chỉ phụ thêm X, Z, Y!
  2. Có thể có những trường hợp không có ý nghĩa gì đối với hằng số enum "cuối cùng" để có chữ "đầu tiên" làm người kế thừa. Hãy suy nghĩ về kích cỡ áo phông cho các ví dụ. XXL.next() chắc chắn không phải XS. Đối với các tình huống như vậy, sử dụng Tùy chọn là câu trả lời phù hợp hơn.
+0

Xin chào, GhostCat. Tôi cho rằng tôi đã không nói rõ điều này trong câu hỏi, nhưng tôi đã hy vọng một giải pháp tự động mở rộng (tức là, không phải là "bạo lực"), theo giả định rằng thứ tự mặc định là một thứ tự hợp lý. Tôi không thực sự nghĩ rằng điều này trả lời câu hỏi, nhưng quan điểm của bạn rằng thứ tự mặc định có thể không được mong muốn thực sự có giá trị. – wchargin

+1

Bạn được chào đón; Tôi chỉ đi qua một số câu hỏi và suy nghĩ khác: đặc biệt là phần Tùy chọn sẽ có giá trị câu trả lời của riêng mình. – GhostCat

+0

Vâng. Tôi thích những gì 'Tùy chọn' có thể và đã cho nó một shot công bằng trong các dự án lớn hơn; nó quá tệ đến nỗi nó không thể tích hợp tốt với phần còn lại của ngôn ngữ. – wchargin

Các vấn đề liên quan