2010-04-25 39 views

Trả lời

90

Enums không chỉ phải đại diện cho các bộ thụ động (ví dụ: màu sắc). Chúng có thể đại diện cho các đối tượng phức tạp hơn với chức năng và do đó, bạn có thể muốn thêm chức năng khác vào các chức năng này - ví dụ: bạn có thể có các giao diện như Printable, Reportable v.v ... và các thành phần hỗ trợ các giao diện này.

+0

Được bỏ phiếu tại sao? –

4

Enums chỉ là lớp học trong ngụy trang, do đó, đối với hầu hết các phần, bất cứ điều gì bạn có thể làm với một lớp học bạn có thể làm với một enum.

Tôi không thể nghĩ ra một lý do khiến một enum không thể thực hiện giao diện, đồng thời tôi cũng không thể nghĩ ra lý do chính đáng cho họ.

Tôi sẽ nói một khi bạn bắt đầu thêm những thứ như giao diện, hoặc phương pháp vào một enum bạn nên thực sự xem xét làm cho nó một lớp thay thế. Tất nhiên tôi chắc chắn có những trường hợp hợp lệ để làm những điều enum phi truyền thống, và vì giới hạn sẽ là một nhân tạo, tôi ủng hộ việc cho phép mọi người làm những gì họ muốn ở đó.

+3

"... vì vậy phần lớn mọi thứ bạn có thể làm với một lớp bạn có thể làm với một enum", nhưng tôi không thể nói có enum của tôi kế thừa từ một lớp trừu tượng. Vì vậy, yeah, nhấn mạnh vào "cho hầu hết các phần". –

+4

Đó là bởi vì tất cả các enums mở rộng java.lang.Enum, và các lớp Java chỉ có thể mở rộng từ một lớp. – TofuBeer

8

Cần thiết cho khả năng mở rộng - nếu ai đó sử dụng API bạn đã phát triển, các enums bạn xác định là tĩnh; họ không thể được thêm vào hoặc sửa đổi. Tuy nhiên, nếu bạn để nó thực hiện một giao diện, người dùng API có thể phát triển enum của riêng họ bằng cách sử dụng cùng một giao diện. Sau đó bạn có thể đăng ký enum này với một người quản lý enum mà tập hợp các enums cùng với giao diện tiêu chuẩn.

Chỉnh sửa: @Helper Method có ví dụ hoàn hảo về điều này. Hãy suy nghĩ về việc có các thư viện khác xác định các toán tử mới và sau đó nói với một lớp người quản lý rằng 'hey, enum này tồn tại - đăng ký nó'. Nếu không, bạn chỉ có thể xác định Toán tử trong mã của riêng bạn - không có khả năng mở rộng.

11

Vì Enums có thể triển khai các giao diện, chúng có thể được sử dụng để thực thi nghiêm ngặt mẫu đơn. Đang cố gắng để tạo ra một lớp tiêu chuẩn một singleton cho phép ...

  • cho khả năng sử dụng các kỹ thuật phản ánh để lộ phương pháp tư nhân như công
  • cho kế thừa từ singleton của bạn và trọng phương pháp của singleton của bạn với cái gì khác

Enums là single giúp ngăn ngừa các vấn đề bảo mật này. Đây có thể là một trong những lý do góp phần để Enums hoạt động như các lớp và thực hiện các giao diện. Chỉ cần đoán thôi.

Xem https://stackoverflow.com/questions/427902/java-enum-singletonSingleton class in java để thảo luận thêm.

+0

'để kế thừa từ singleton của bạn và ghi đè các phương pháp của bạn với một cái gì đó khác'. bạn chỉ có thể sử dụng một 'lớp cuối cùng' để ngăn chặn điều đó – Dylanthepiguy

217

Dưới đây là một ví dụ (tương tự/một tốt hơn được tìm thấy trong Effective Java 2nd Edition):

public interface Operator { 
    int apply (int a, int b); 
} 

public enum SimpleOperators implements Operator { 
    PLUS { 
     int apply(int a, int b) { return a + b; } 
    }, 
    MINUS { 
     int apply(int a, int b) { return a - b; } 
    }; 
} 

public enum ComplexOperators implements Operator { 
    // can't think of an example right now :-/ 
} 

Bây giờ để có được một danh sách của cả hai đơn giản + Các nhà khai thác Complex:

List<Operator> operators = new ArrayList<Operator>(); 

operators.addAll(Arrays.asList(SimpleOperators.values())); 
operators.addAll(Arrays.asList(ComplexOperators.values())); 

Vì vậy, ở đây bạn sử dụng một giao diện để mô phỏng enums mở rộng (mà sẽ không thể được mà không cần sử dụng một giao diện).

+2

Các toán tử phức tạp có thể là" pow "và tương tự. – Pimgd

0

Bạn có thể làm được nhiều việc hơn với enum s. Bạn có thể thêm các phương thức và các đối số hàm tạo cho chúng. Bạn có thể thực hiện Comparable để enum của bạn để so sánh chúng. Ngoài ra, enum là các lớp, do đó, việc triển khai giao diện nên được cho phép.

enum Planet implements Comparable<Planet> { 
    EARTH(1), 
    MARS(3); // ... and so on 

    public final float distance; 
    Planet(float distance) { 
    this.distance = distance; 
    } 
    // compare distances 
    public int compareTo(Planet other) { 
    return this.distance - other.distance; 
    } 
    // sorry, I didnt check my code 
} 
+12

Không. Lớp cơ sở 'Enum' đã triển khai' So sánh' và bạn không thể ghi đè quá trình triển khai đó. – Jorn

19

Các Comparable ví dụ đưa ra bởi nhiều người dân ở đây là sai, vì Enum đã thực hiện điều đó. Bạn thậm chí không thể ghi đè lên nó.

Ví dụ tốt hơn là có giao diện xác định, ví dụ: kiểu dữ liệu. Bạn có thể có một enum để thực hiện các loại đơn giản, và có các lớp học bình thường để thực hiện các loại phức tạp:

interface DataType { 
    // methods here 
} 

enum SimpleDataType implements DataType { 
    INTEGER, STRING; 

    // implement methods 
} 

class IdentifierDataType implements DataType { 
    // implement interface and maybe add more specific methods 
} 
+2

Yes.Chúng tôi !! Enum đã thực hiện giao diện Comparable và không cho phép ghi đè lên. Tôi nhìn lên mã nguồn java cho lớp enum và không thể tìm thấy việc thực hiện compareTo. Bất cứ ai có thể cho tôi biết whats được so sánh bên trong một phương pháp compareTo một ENUM? – AKh

+2

@AKh nó so sánh các số thứ tự, có nghĩa là thứ tự tự nhiên là thứ tự các hằng số enum nằm trong tệp nguồn. – Jorn

5

Ví dụ nếu bạn có một Logger enum. Sau đó, bạn nên có các phương pháp logger như gỡ lỗi, thông tin, cảnh báo và lỗi trong giao diện. Nó làm cho mã của bạn lỏng lẻo cùng.

2

Enums giống như Java Classes, chúng có thể có Constructors, Methods, vv Điều duy nhất bạn không thể làm với chúng là new EnumName(). Các cá thể được xác định trước trong khai báo enum của bạn.

+0

Điều gì về 'enum Foo mở rộng SomeOtherClass'? Vì vậy, không hoàn toàn giống như một lớp học thông thường, trên thực tế, khá khác nhau. –

+0

@Adam: Tôi sẽ nói rằng các cách thức mà Enums giống với các lớp học nhiều hơn rất nhiều so với những cách mà chúng khác với các lớp. Nhưng, không, chúng không giống nhau. – scottb

+0

nếu bạn dịch ngược một enum, bạn sẽ thấy đó là một lớp mở rộng liệt kê và có "hằng số" đã được khởi tạo trong các trường khởi tạo/khởi tạo. –

8

Có trường hợp tôi thường sử dụng. Tôi có một lớp IdUtil với các phương pháp tĩnh để làm việc với các đối tượng thực hiện một giao diện rất đơn giản Identifiable:

public interface Identifiable<K> { 
    K getId(); 
} 


public abstract class IdUtil { 

    public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) { 
     for (T t : type.getEnumConstants()) { 
      if (Util.equals(t.getId(), id)) { 
       return t; 
      } 
     } 
     return null; 
    } 

    public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) { 
     List<T> list = new ArrayList<>(); 
     for (T t : en.getDeclaringClass().getEnumConstants()) { 
      if (t.getId().compareTo(en.getId()) < 0) { 
       list.add(t); 
      } 
     } 
     return list; 
    } 
} 

Nếu tôi tạo ra một Identifiableenum:

public enum MyEnum implements Identifiable<Integer> { 

     FIRST(1), SECOND(2); 

     private int id; 

     private MyEnum(int id) { 
      this.id = id; 
     } 

     public Integer getId() { 
      return id; 
     } 

    } 

Sau đó, tôi có thể nhận được nó bằng cách id của nó theo cách này :

MyEnum e = IdUtil.get(MyEnum.class, 1); 
3

Một trong những trường hợp sử dụng tốt nhất để tôi sử dụng enum với i nterface là bộ lọc Predicate. Đó là cách rất thanh lịch để khắc phục thiếu typness của bộ sưu tập apache (Nếu các thư viện khác có thể không được sử dụng).

import java.util.ArrayList; 
import java.util.Collection; 

import org.apache.commons.collections.CollectionUtils; 
import org.apache.commons.collections.Predicate; 


public class Test { 
    public final static String DEFAULT_COMPONENT = "Default"; 

    enum FilterTest implements Predicate { 
     Active(false) { 
      @Override 
      boolean eval(Test test) { 
       return test.active; 
      } 
     }, 
     DefaultComponent(true) { 
      @Override 
      boolean eval(Test test) { 
       return DEFAULT_COMPONENT.equals(test.component); 
      } 
     } 

     ; 

     private boolean defaultValue; 

     private FilterTest(boolean defautValue) { 
      this.defaultValue = defautValue; 
     } 

     abstract boolean eval(Test test); 

     public boolean evaluate(Object o) { 
      if (o instanceof Test) { 
       return eval((Test)o); 
      } 
      return defaultValue; 
     } 

    } 

    private boolean active = true; 
    private String component = DEFAULT_COMPONENT; 

    public static void main(String[] args) { 
     Collection<Test> tests = new ArrayList<Test>(); 
     tests.add(new Test()); 

     CollectionUtils.filter(tests, FilterTest.Active); 
    } 
} 
1

Dưới đây là lý do tại sao tôi ...

Tôi đã cư một JavaFX ComboBox với các giá trị của một Enum. Tôi có một giao diện, có thể nhận dạng (chỉ định một phương thức: xác định), cho phép tôi chỉ định cách thức bất kỳ đối tượng nào tự nhận dạng ứng dụng của tôi cho mục đích tìm kiếm. Giao diện này cho phép tôi quét danh sách của bất kỳ loại đối tượng nào (bất kỳ trường nào đối tượng có thể sử dụng để nhận dạng) cho một kết hợp nhận dạng.

Tôi muốn tìm một kết quả phù hợp với giá trị danh tính trong danh sách ComboBox của tôi. Để sử dụng khả năng này trên ComboBox của tôi có chứa các giá trị Enum, tôi phải có khả năng thực hiện giao diện Identifiable trong Enum của tôi (trong đó, khi nó xảy ra, là tầm thường để thực hiện trong trường hợp của một Enum).

3

Cách sử dụng phổ biến nhất cho việc này là hợp nhất các giá trị của hai enums thành một nhóm và xử lý chúng tương tự nhau. Ví dụ: xem cách join Fruits and Vegatables.

0

Tôi đã sử dụng một enum bên trong trong một giao diện mô tả một chiến lược để giữ quyền kiểm soát cá thể (mỗi chiến lược là một Singleton) từ đó.

public interface VectorizeStrategy { 

    /** 
    * Keep instance control from here. 
    * 
    * Concrete classes constructors should be package private. 
    */ 
    enum ConcreteStrategy implements VectorizeStrategy { 
     DEFAULT (new VectorizeImpl()); 

     private final VectorizeStrategy INSTANCE; 

     ConcreteStrategy(VectorizeStrategy concreteStrategy) { 
      INSTANCE = concreteStrategy; 
     } 

     @Override 
     public VectorImageGridIntersections processImage(MarvinImage img) { 
      return INSTANCE.processImage(img); 
     } 
    } 

    /** 
    * Should perform edge Detection in order to have lines, that can be vectorized. 
    * 
    * @param img An Image suitable for edge detection. 
    * 
    * @return the VectorImageGridIntersections representing img's vectors 
    * intersections with the grids. 
    */ 
    VectorImageGridIntersections processImage(MarvinImage img); 
} 

Thực tế là enum thực hiện chiến lược thuận tiện để cho phép lớp enum hoạt động như proxy cho trường hợp kèm theo. cũng thực hiện giao diện.

đó là một loại strategyEnumProxy: P mã clent trông như thế này:

VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img); 

Nếu nó không thực hiện giao diện nó muốn đã:

VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img); 
0

posibility Một:

public enum ConditionsToBeSatisfied implements Predicate<Number> { 
    IS_NOT_NULL(Objects::nonNull, "Item is null"), 
    IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"), 
    IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative"); 

    private final Predicate<Number> predicate; 
    private final String notSatisfiedLogMessage; 

    ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) { 
     this.predicate = predicate; 
     this.notSatisfiedLogMessage = notSatisfiedLogMessage; 
    } 

    @Override 
    public boolean test(final Number item) { 
     final boolean isNotValid = predicate.negate().test(item); 

     if (isNotValid) { 
      log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage); 
     } 

     return predicate.test(item); 
    } 
} 

và sử dụng:

Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE); 
Các vấn đề liên quan