2012-01-10 45 views
5

Tôi có một câu hỏi liên quan đến mẫu thiết kế tốt nhất để sử dụng lại mã khi xử lý các enum Java. Về cơ bản, những gì tôi đang cố gắng đạt được là có thể xác định một số enums mô hình hóa các bộ sưu tập kinh doanh tĩnh (bộ các hằng số), nhưng tôi cũng muốn chia sẻ hành vi giữa chúng, với mã hóa tối thiểu. Điều này là tầm thường để đạt được với kế thừa lớp từ lớp trừu tượng nhưng, vì Java enums không thể được mở rộng (họ chỉ có thể thực hiện giao diện), loại công việc này tẻ nhạt và liên quan đến rất nhiều công việc sao chép/dán dễ bị lỗi (sao chép). Quay lại đầu trang mã từ enum đến enum). Ví dụ về "logic nghiệp vụ" cần được chia sẻ giữa tất cả các enums bao gồm chuyển đổi từ/thành chuỗi, ví dụ và so sánh lôgic, v.v.Mở rộng Java Enums

Ảnh tốt nhất hiện tại của tôi là sử dụng lớp trợ giúp kết hợp với giao diện kinh doanh, nhưng điều này chỉ cho đến nay trong việc giảm độ phức tạp của mã (vì tất cả các enums vẫn phải khai báo và gọi các lớp trợ giúp). Xem ví dụ (chỉ để làm rõ):

public enum MyEnum { 
    A, B, C; 

    // Just about any method fits the description - equals() is a mere example 
    public boolean equals(MyEnum that) { 
     ObjectUtils.equals(this, that); 
    } 
} 

Làm thế nào để StackOverflowers đối phó với "tính năng ngôn ngữ" này?

+0

thể thử Lombok và '@ Delegate', tôi đã không bao giờ đã thử nó với một enum. –

+0

Trong Java 6, enums là một lớp cuối cùng; bạn không thể mở rộng chúng. Tôi tin rằng java 7 là như nhau. – DwB

+1

Enums không được thực hiện cho điều đó: hoặc sử dụng các lớp (hoặc các lớp với enums) hoặc tách logic; bạn có thể sử dụng một mẫu nhà máy cho một trường hợp như thế này (nếu hành vi này là đủ khác nhau từ enum để enum). – Viruzzo

Trả lời

2

Tôi sẽ làm tương tự, hoặc kết hợp Enums thành một siêu enum.

Với Java 8 việc này sẽ dễ dàng hơn. Bạn sẽ có thể xác định triển khai default cho các phương thức giao diện và mở rộng giao diện enum.

+0

Bạn có ý gì với việc kết hợp 'enum' thành một siêu -'enum'? Điều đó sẽ không an toàn khi giá trị A và B có thể được so sánh ngay cả khi nó không có ý nghĩa? – lsoliveira

+0

Nó có thể không an toàn, nó phụ thuộc vào ngữ cảnh. –

+0

Cuối cùng, tất cả các giải pháp khác thêm phức tạp hơn mà không vi phạm nguyên tắc DRY, vì vậy đây có vẻ là giải pháp. Các lớp mở rộng ngón tay của tôi đến với Java, một ngày nào đó ... – lsoliveira

2

Tôi hiếm khi tìm thấy enums hữu ích, ngoại trừ đại diện cho các trạng thái hữu hạn trong trường hợp chúng không cần hành vi.

Tôi sẽ đề xuất tái cấu trúc enums cần hành vi vào classes với số Factory.

+0

enums an toàn hơn nhiều so với sử dụng hằng số để truyền xung quanh các giá trị và cho vay tốt hơn rất nhiều để thao tác (EnumSet <...>, 'switch', v.v.). Tôi đồng ý rằng họ là ít hơn rất nhiều so với đối tác C# của họ, nhưng họ vẫn có vị trí của họ (đặc biệt là khi bạn chỉ refactoring một số mã và không thể làm một viết lại hoàn toàn :)). – lsoliveira

+0

Tôi đồng ý 'enums' tốt hơn' cũ static int CONSTANT = 1' và cú pháp đường là tốt đẹp, nhưng mỗi khi tôi đã đặt hành vi trong một 'enum' tôi đã hối hận về nó. –

+0

@Isoliveira Đợi ** LESS ** mạnh mẽ hơn C# enums về cơ bản là cú pháp đường xung quanh một int? Làm thế nào bạn đi đến kết luận đó? Dù sao tôi đồng ý với Garett ở một mức độ nào đó: Enums có mặt để đại diện cho các bang hữu hạn trong trường hợp đó tôi không chắc tại sao chúng ta cần mở rộng chúng. Nhưng có một số trạng thái đơn giản (!) Trong enums thường hữu ích. Nếu nó là nhiều hơn phương pháp tầm thường nó phải là một lớp học mặc dù. Nhưng ví dụ: phương thức 'getComplement()' sẽ ổn trong cuốn sách của tôi. – Voo

3

Bạn có thể di chuyển lôgic có thể tái sử dụng sang các lớp chuyên dụng (không phải enum) và sau đó có enums ủy nhiệm cho các lớp đó. Dưới đây là ví dụ:

[Ghi chú bên: không được khuyến khích thừa kế PlusTwo extends PlusOne (b/c PlusTwo không phải là PlusOne). Ở đây chỉ để minh họa quan điểm của việc có thể mở rộng một logic hiện có.]

public interface Logic { 
    public int calc(int n); 
} 

public static class PlusOne implements Logic { 
    public int calc(int n) { return n + 1; } 
} 

public static class PlusTwo extends PlusOne { 
    @Override 
    public int calc(int n) { return super.calc(n) + 1; } 
} 

public static enum X { 
    X1, X2; 
    public Logic logic; 

    public int doSomething() { 
    return logic.calc(10); 
    } 
} 

public static enum Y { 
    Y1, Y2; 
    public Logic logic; 

    public String doSomethingElse() { 
    return "Your result is '" + logic.calc(10) + "'"; 
    } 
} 

public static void main(String[] args) { 
    // One time setup of your logic: 
    X.X1.logic = new PlusOne(); 
    X.X2.logic = new PlusTwo(); 
    Y.Y1.logic = new PlusOne(); 
    Y.Y2.logic = new PlusTwo(); 

    System.out.println(X.X1.doSomething()); 
    System.out.println(X.X2.doSomething()); 
    System.out.println(Y.Y1.doSomethingElse()); 
    System.out.println(Y.Y2.doSomethingElse()); 
} 
+0

Cuối cùng, đó chỉ là một biến thể trong đề xuất ban đầu của tôi. Nó chỉ tách rời logic thực hiện. Tôi cũng sẽ sử dụng một nhà máy cho 'Logic' và không có nó tiếp xúc như thế (như tôi chắc chắn bạn sẽ quá, nếu không cho điều này chỉ là một ví dụ). – lsoliveira

0

Điều này có thể hơi xấu xí, nhưng thường có thể cung cấp cho bạn chức năng được yêu cầu.

Bạn có thể có giao diện

public interface MyEnumInterface<T extends Enum<T>> { 

    String getBusinessName(); 

    T getEnum(); 

} 

Thực hiện

public enum OneOfMyEnums implements MyEnumInterface<OneOfMyEnums>{ 

    X, Y, Z; 

    @Override 
    public String getBusinessName() { 
     return "[OneOfMyEnums]" + name(); 
    } 

    @Override 
    public OneOfMyEnums getEnum() { 
     return this; 
    } 

} 

Và tiện ích lớp thay vì lớp cha mẹ của bạn

public class MyEnumUtils { 

    public static <T extends Enum<T>> String doSomething(MyEnumInterface<T> e){ 
     e.getBusinessName(); // can use MyEnumInterface methods 
     e.getEnum().name(); // can use Enum methods as well 
     return null; 
    } 

} 
+0

Cách tiếp cận này là thú vị nhưng đảo ngược hợp đồng bằng cách làm cho máy khách dựa vào các lớp tiện ích thay vì 'enum' (phương thức 'equals()' đi vào 'MyEnumUtils'). – lsoliveira