Respostas:
As enums não precisam apenas representar conjuntos passivos (por exemplo, cores). Eles podem representar objetos mais complexos com funcionalidade e, portanto, é provável que você queira adicionar mais funcionalidades a eles - por exemplo, você pode ter interfaces como Printable
, Reportable
etc. , e componentes que os suportem.
Aqui está um exemplo (um similar / melhor é encontrado no 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 :-/
}
Agora, para obter uma lista dos dois operadores simples e complexos:
List<Operator> operators = new ArrayList<Operator>();
operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));
Então, aqui você usa uma interface para simular enums extensíveis (o que não seria possível sem o uso de uma interface).
O Comparable
exemplo dado por várias pessoas aqui está errado, pois Enum
já o implementa. Você nem pode substituí-lo.
Um exemplo melhor é ter uma interface que define, digamos, um tipo de dados. Você pode ter uma enumeração para implementar os tipos simples e ter classes normais para implementar tipos complicados:
interface DataType {
// methods here
}
enum SimpleDataType implements DataType {
INTEGER, STRING;
// implement methods
}
class IdentifierDataType implements DataType {
// implement interface and maybe add more specific methods
}
Há um caso que eu frequentemente uso. Eu tenho uma IdUtil
classe com métodos estáticos para trabalhar com objetos implementando uma Identifiable
interface muito simples :
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;
}
}
Se eu criar um Identifiable
enum
:
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;
}
}
Então eu posso obtê-lo id
desta forma:
MyEnum e = IdUtil.get(MyEnum.class, 1);
Como os Enums podem implementar interfaces, eles podem ser usados para impor rigorosamente o padrão singleton. Tentando fazer uma classe padrão um singleton permite ...
Enums como singletons ajudam a evitar esses problemas de segurança. Esse pode ter sido um dos motivos que contribuíram para permitir que o Enums atue como classes e implemente interfaces. Apenas um palpite.
Consulte /programming/427902/java-enum-singleton e a classe Singleton em java para obter mais discussão.
for inheriting from your singleton and overriding your singleton's methods with something else
. você pode simplesmente usar um final class
para evitar que
É necessário extensibilidade - se alguém usa uma API que você desenvolveu, as enumerações que você define são estáticas; eles não podem ser adicionados ou modificados. No entanto, se você permitir implementar uma interface, a pessoa que usa a API pode desenvolver sua própria enumeração usando a mesma interface. Em seguida, você pode registrar essa enumeração com um gerenciador de enumerações que conglomera as enumerações junto com a interface padrão.
Edit: @Helper Method tem o exemplo perfeito disso. Pense em ter outras bibliotecas definindo novos operadores e depois dizendo a uma classe gerenciadora que 'ei, essa enum existe - registre-a'. Caso contrário, você só poderá definir Operadores em seu próprio código - não haverá extensibilidade.
Enums são apenas classes disfarçadas; portanto, na maior parte do tempo, qualquer coisa que você possa fazer com uma classe pode fazer com uma enumeração.
Não consigo pensar em uma razão para que um enum não consiga implementar uma interface, ao mesmo tempo não consigo pensar em uma boa razão para isso.
Eu diria que, quando você começar a adicionar coisas como interfaces ou método a uma enumeração, considere realmente torná-la uma classe. É claro que tenho certeza de que existem casos válidos para fazer enum não tradicionais e, como o limite seria artificial, sou a favor de deixar as pessoas fazerem o que querem lá.
O uso mais comum para isso seria mesclar os valores de duas enums em um grupo e tratá-los da mesma forma. Por exemplo, veja como ingressar no Fruits and Vegatables .
Um dos melhores casos de uso para eu usar enum's com interface são os filtros de predicado. É uma maneira muito elegante de corrigir a falta de tipicidade das coleções apache (se outras bibliotecas não puderem ser usadas).
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);
}
}
A publicação acima mencionada estratégias não enfatizou o suficiente o que uma implementação leve e agradável do padrão de estratégia usando enumeras faz com que você:
public enum Strategy {
A {
@Override
void execute() {
System.out.print("Executing strategy A");
}
},
B {
@Override
void execute() {
System.out.print("Executing strategy B");
}
};
abstract void execute();
}
Você pode ter todas as suas estratégias em um só lugar sem precisar de uma unidade de compilação separada para cada uma. Você recebe um bom envio dinâmico apenas com:
Strategy.valueOf("A").execute();
Faz com que o Java seja lido quase como uma linguagem agradável e tipicamente digitada!
As enums são como classes Java, elas podem ter construtores, métodos etc. A única coisa que você não pode fazer com elas é new EnumName()
. As instâncias são predefinidas na sua declaração enum.
enum Foo extends SomeOtherClass
? Portanto, não é exatamente a mesma coisa que uma aula regular, de fato, bem diferente.
Outra possibilidade:
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);
}
}
e usando:
Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
Ao criar constantes em um arquivo jar, geralmente é útil permitir que os usuários estendam valores de enumeração. Usamos enumerações para chaves PropertyFile e ficamos paralisadas porque ninguém poderia adicionar novas! Abaixo teria funcionado muito melhor.
Dado:
public interface Color {
String fetchName();
}
e:
public class MarkTest {
public static void main(String[] args) {
MarkTest.showColor(Colors.BLUE);
MarkTest.showColor(MyColors.BROWN);
}
private static void showColor(Color c) {
System.out.println(c.fetchName());
}
}
alguém poderia ter um enum no pote:
public enum Colors implements Color {
BLUE, RED, GREEN;
@Override
public String fetchName() {
return this.name();
}
}
e um usuário pode estendê-lo para adicionar suas próprias cores:
public enum MyColors implements Color {
BROWN, GREEN, YELLOW;
@Override
public String fetchName() {
return this.name();
}
}
Aqui está a minha razão pela qual ...
Eu preenchi uma JavaFX ComboBox com os valores de um Enum. Eu tenho uma interface, identificável (especificando um método: identificar), que permite especificar como qualquer objeto se identifica para o meu aplicativo para fins de pesquisa. Essa interface permite verificar listas de qualquer tipo de objetos (qualquer que seja o campo que o objeto possa usar para identidade) para uma correspondência de identidade.
Gostaria de encontrar uma correspondência para um valor de identidade na minha lista ComboBox. Para usar esse recurso no meu ComboBox que contém os valores de Enum, devo poder implementar a interface Identificável no meu Enum (que, por acaso, é trivial de implementar no caso de um Enum).
Eu usei um enum interno em uma interface que descreve uma estratégia para manter o controle da instância (cada estratégia é um Singleton) a partir daí.
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);
}
O fato de o enum implementar a estratégia é conveniente para permitir que a classe enum atue como proxy para sua Instância fechada. que também implementa a interface.
é um tipo de strategyEnumProxy: P o código clent se parece com isso:
VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);
Se não implementasse a interface, teria sido:
VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);