我刚刚发现Java允许枚举实现接口。它的一个好的用例是什么?


当前回答

它是可扩展性所必需的——如果有人使用您开发的API,则您定义的枚举是静态的;它们不能被添加或修改。但是,如果让它实现一个接口,使用API的人可以使用相同的接口开发自己的枚举。然后,您可以向枚举管理器注册这个枚举,枚举管理器将枚举与标准接口结合在一起。

Edit: @Helper方法有一个完美的例子。考虑让其他库定义新的操作符,然后告诉管理器类“嘿,这个枚举存在——注册它”。否则,您只能在自己的代码中定义操作符——就没有可扩展性了。

其他回答

上面提到的策略并没有充分强调使用枚举的策略模式的轻量级实现:

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

你可以把所有的策略放在一个地方,而不需要为每个策略单独编译单元。你得到了一个很好的动态调度:

Strategy.valueOf("A").execute();

使java读起来几乎像一种美味的松散类型语言!

枚举不只是表示被动的集合(例如颜色)。它们可以表示具有功能的更复杂的对象,因此你可能想要在这些对象上添加更多的功能——例如,你可能有诸如Printable、Reportable等接口,以及支持这些接口的组件。

下面是一个例子(在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()));

因此,在这里您使用一个接口来模拟可扩展枚举(如果不使用接口,这是不可能的)。

另一个可能性:

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

这里一些人给出的可比示例是错误的,因为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
}