2010-04-25 22 views

ответ

90

Режимы не просто должны представлять пассивные наборы (например, цвета). Они могут представлять более сложные объекты с функциональностью, и поэтому вы, вероятно, захотите добавить к ним дополнительные функции - например, у вас могут быть такие интерфейсы, как Printable, Reportable и т. д. и компоненты, которые их поддерживают.

+0

Продвинутый вопрос: почему? –

4

Enums - это просто маскировка классов, поэтому, по большей части, все, что вы можете сделать, с классом, который вы можете сделать с перечислением.

Я не могу придумать, почему переименование не должно быть в состоянии реализовать интерфейс, в то же время я не могу придумать для них вескую причину.

Я бы сказал, что как только вы начнете добавлять вещи, такие как интерфейсы или метод к перечислению, вы должны действительно подумать о том, чтобы сделать его классом. Конечно, я уверен, что существуют действительные случаи для выполнения нетрадиционных перечислений, и поскольку предел будет искусственным, я за то, чтобы позволить людям делать то, что они там хотят.

+3

«... так что по большей части все, что вы можете сделать с классом, который вы можете сделать с перечислением», но я не могу сказать, что мой enum наследуется от абстрактного класса. Так что да, акцент на «по большей части». –

+4

Это потому, что перечисления расширяют java.lang.Enum, а классы Java могут распространяться только из одного класса. – TofuBeer

8

Это необходимо для расширяемости - если кто-то использует разработанный вами API, перечисления, которые вы определяете, являются статическими; они не могут быть добавлены или изменены. Однако, если вы позволите ему реализовать интерфейс, человек, использующий API, может разработать собственное перечисление, используя тот же интерфейс. Затем вы можете зарегистрировать это перечисление с помощью менеджера перечислений, который объединяет перечисления вместе со стандартным интерфейсом.

Редактировать: метод @Helper имеет прекрасный пример этого. Подумайте о том, что другие библиотеки определяют новые операторы, а затем сообщают классу менеджера, что «эй, это перечисление существует - зарегистрируйте его». В противном случае вы сможете определять операторы только в своем собственном коде - не было бы расширяемости.

11

Поскольку Enums может реализовать интерфейсы, они могут использоваться для строгого соблюдения одноэлементного шаблона. Попытка сделать стандартный класс одноэлементно позволяет ...

  • для возможности использования методов отражения разоблачить частные методы, как общественный
  • для наследования от вашего одноточечного и переопределения методов вашего Синглтона с чем-то другими

Перечисления в качестве однопользовательских систем помогают предотвратить эти проблемы безопасности. Возможно, это была одна из причин, по которым Enums может действовать как классы и реализовывать интерфейсы. Просто догадка.

См. https://stackoverflow.com/questions/427902/java-enum-singleton и Singleton class in java для более подробного обсуждения.

+0

'для наследования от вашего синглтона и переопределения методов вашего синглтона с чем-то еще. вы можете просто использовать «последний класс», чтобы предотвратить то, что – Dylanthepiguy

217

Вот один пример (подобный/лучше один находится в 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 :-/ 
} 

Теперь, чтобы получить список обоих простых + сложных операторов:

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

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

Так здесь вы используете интерфейс для имитации расширяемых перечислений (что было бы невозможно без использования интерфейса).

+2

Сложные операторы могут быть «pow» и тому подобное. – Pimgd

0

Вы можете сделать гораздо больше с помощью enum s. Вы можете добавить к ним методы и аргументы конструктора. Вы можете применить Comparable к вашему перечислению, чтобы сравнить их. Кроме того, enum s являются классами, поэтому реализация интерфейса должна быть разрешена.

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

№. Базовый класс 'Enum' уже реализует' Comparable', и вы не можете переопределить эту реализацию. – Jorn

19

Comparable пример, приведенный несколько людей здесь не так, так как Enum уже реализует это. Вы даже не можете его переопределить.

Лучшим примером является интерфейс, который определяет, скажем, тип данных. Вы можете иметь перечисление реализовать простые типы, и имеют нормальные классы для реализации сложных типов:

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.Weird !!. Enum уже реализует интерфейс Comparable и не позволяет переопределить. Я искал исходный код Java для класса enum и не смог найти реализацию compareTo. Может ли кто-нибудь сказать мне, что сравнивается в методе compareTo с ENUM? – AKh

+2

@AKh сравнивает ординалы, то есть естественное упорядочение - это порядок, в котором константы перечисления находятся в исходном файле. – Jorn

5

Например, если у вас есть Logger ENUM. Затем вы должны иметь методы регистрации, такие как debug, info, warning и error в интерфейсе. Это делает ваш код слабо связанным.

2

Перечисления как Java-классы, они могут иметь конструкторы, методы и т. Д. Единственное, что вы не можете с ними сделать, это new EnumName(). Экземпляры предопределены в объявлении перечисления.

+0

Как насчет 'enum Foo extends SomeOtherClass'? Так что не совсем то же самое, что и обычный класс, по сути, совсем другой. –

+0

@Adam: Я бы сказал, что способы, с помощью которых Enums напоминают классы, намного более многочисленны, чем способы, которыми они отличаются от классов. Но нет, они не идентичны. – scottb

+0

, если вы декомпилируете перечисление, вы увидите, что это класс, который расширяет Enumeration и имеет «константы», уже созданные в полях конструктора/инициализации. –

8

Существует случай, который я часто использую. У меня есть IdUtil класса со статическими методами работы с объектами реализации очень простой 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; 
    } 
} 

Если я создать 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; 
     } 

    } 

Тогда я могу получить его по id этот путь :

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

Один из лучших вариантов использования для использования enum's с i nterface - это предикатные фильтры. Это очень элегантный способ устранить недостаток типичности коллекций apache (если другие библиотеки не могут использоваться).

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

Вот моя причина ...

Я заселена с JavaFX ComboBox со значениями в Enum. У меня есть интерфейс, идентифицируемый (с указанием одного метода: идентификация), который позволяет мне указать, как любой объект идентифицирует себя в моем приложении для поиска. Этот интерфейс позволяет мне сканировать списки объектов любого типа (в зависимости от того, какое поле может использовать объект для идентификации) для соответствия идентичности.

Я хотел бы найти соответствие для значения идентификатора в моем списке ComboBox. Чтобы использовать эту возможность в моем ComboBox, содержащем значения Enum, я должен иметь возможность реализовать интерфейс Identifiable в моем Enum (который, как это бывает, тривиально реализовать в случае Enum).

3

Наиболее распространенным использованием для этого было бы объединить значения двух перечислений в одну группу и относиться к ним аналогичным образом. Например, см., Как join Fruits and Vegatables.

0

Я использовал внутреннее перечисление в интерфейсе, описывающем стратегию сохранения контроля экземпляра (каждая стратегия - Синглтон) оттуда.

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); 
} 

Тот факт, что перечисление реализует стратегию удобно, чтобы класс перечисление действовать в качестве прокси-сервера для его закрытых Instance. который также реализует интерфейс.

это своего рода strategyEnumProxy: P код клент выглядит следующим образом:

VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img); 

Если он не реализует интерфейс, что бы он был:

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

Другой вешать:

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); 
    } 
} 

и использование:

Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE); 
Смежные вопросы