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


当前回答

由于枚举可以实现接口,它们可以用于严格执行单例模式。试着让一个标准类成为单例允许…

获奖理由:可以使用反射技术将私有方法公开为公共方法 用于从你的单例中继承和用其他东西重写你的单例方法

作为单例的枚举有助于防止这些安全问题。这可能是让enum充当类并实现接口的原因之一。只是猜测。

更多讨论请参见https://stackoverflow.com/questions/427902/java-enum-singleton和java中的Singleton类。

其他回答

我在一个接口中使用了一个内部枚举来描述一个策略来保持实例控制(每个策略都是一个Singleton)。

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

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

枚举只是伪装的类,所以在大多数情况下,可以用类做的任何事情都可以用枚举做。

我想不出一个理由,enum不应该能够实现接口,同时我也想不出一个好的理由。

我想说的是,一旦你开始往枚举中添加接口或方法,你应该考虑把它变成一个类。当然,我确信有一些案例可以用于执行非传统枚举内容,而且由于限制是人为的,所以我赞成让人们在枚举中做他们想做的事情。

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

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

另一个可能性:

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