强制实现枚举的Java接口 - 如何处理?

时间:2018-05-19 10:41:23

标签: java enums interface

我有一种情况,我想使用一个名为Abstraction的对象的实例,它将是一个Java界面,如下所示:

public interface Abstraction {
   public enum Actions {
   }
}

任何实现Abstraction的类都必须实现枚举动作(我意识到这不起作用)。

实现接口的类可能如下所示:

public class AbstractionA implements Abstraction {
   public enum Actions {
    f, c, r, a
   }
}

在另一个课程中,我想创建一个Abstraction对象,如:

Abstraction abs = new AbstractionA();

然后能够访问适用于创建的Abstraction对象的枚举值,例如

abs.Action.r;

我意识到我对此的态度是错误的,但却找不到适当的方法来处理这种情况。我如何实现这样的东西,其中接口的不同实现具有我通常想要放入枚举的选项的不同子集? 也许我可以在界面中使用所有可能的选项实现枚举,然后以某种方式限制接口的实现以使用这些枚举值的子集?

编辑: 另一个示例实现可能是

public class AbstractionB implements Abstraction {
   public enum Actions {
    f, c, b, r, a
   }
}

我想我已经找到了前进的方法:

public interface Abstraction {
   public enum Actions {
    f, c, b, r, s, a  
   }
   public Actions[] availableActions();
}

然后执行:

public class HunlAbstractionA implements Abstraction{
   @Override
   public Actions[] availableActions()
   {
    Actions[] actions = new Actions[] {Actions.f, Actions.c, Actions.r, Actions.a};
    return actions;
   }
}

通过这种方式,我可以访问interfaces枚举中列出的所有可能操作,并可以进行检查以确保要处理的Action是已创建类的availableActions之一。

2 个答案:

答案 0 :(得分:0)

接口是您希望任何人提供该合同的实施的合同。在您的示例代码中,您没有方法,只有一个名为Action的枚举的定义。

一般来说,枚举是一组常量,因此我们不希望多个类提出相同常量的不同实现。

因此,您可能想重新考虑一下您的方法并找出更好的方法。希望这将有助于您朝着正确的方向前进。

答案 1 :(得分:0)

建议

我建议采用以下方法。

这种方法使用泛型和反射的组合来帮助明确指出需要实现或选择适当的枚举,它还为您提供了保留有关枚举类型的信息同时隐藏有关特定抽象实现的所有其他信息的选项。

/**
 * An abstraction with an implementation-defined enum
 * @param <E> your custom enum.
 */
interface Abstraction<E extends Enum> {

    //this gives you the enum constants as a list
    Class<E> getEnumType();

}

class AbstractionA implements Abstraction<AbstractionA.EnumA> {
    enum EnumA {
        FOO,
        BAR
    }

    @Override
    public Class<EnumA> getEnumType() {
        return EnumA.class;
    }
}

class AbstractionB implements Abstraction<AbstractionB.EnumB> {
    enum EnumB {
        FOO,
        BAR
    }

    @Override
    public Class<EnumB> getEnumType() {
        return EnumB.class;
    }
}

请注意,遗憾的是,由于type erasure,我们可以提供getEnumType()的默认实现。

用法示例

class Main {
    public static void main(String[] args) {
        Abstraction myAbstractionA = new AbstractionA();
        Abstraction<AbstractionB.EnumB> myAbstractionB = new AbstractionB();

        Class enumAType = myAbstractionA.getEnumType();
        Class<AbstractionB.EnumB> enumBType = myAbstractionB.getEnumType();
        Object[] enumsA = enumAType.getEnumConstants();
        AbstractionB.EnumB[] enumsB = enumBType.getEnumConstants();
        System.out.printf("Enums of the same order are still non-identical: %s", enumsA[0].equals(enumsB[0]));
        System.out.println();

        Enum enumA = ((Enum)enumsA[0]);
        Enum enumB = ((Enum)enumsB[1]);
        System.out.printf("We can get enum constants in order, and get the orderinal of the enum: A=%s, B=%s", enumA.ordinal(), enumB.ordinal());
        System.out.println();

        enumA = Enum.valueOf(enumAType, "FOO");
        enumB = Enum.valueOf(enumBType, "BAR");
        System.out.printf("We can get enum constants by name and get the name out of the enum: A=%s, B=%s", enumA.name(), enumB.name());
        System.out.println();
    }
}

替代

如果您可以使用抽象类而不是接口,则可能更喜欢类似于this related answer的解决方案。

编辑:如果您想要在操作中共享一组通用常量,则应该对这些常量使用全局/共享枚举,并在自定义抽象中仅定义扩展本身。如果你把它们全部投射到Enum并根据需要使用.equals(),这在大多数情况下都适用。

背景

正如您所知,可以放置接口的成员对象(变量或类)。

然而,好消息是java实际上支持你想要的行为。

有三个与我的建议相关的关键功能:

枚举是对象

首先,java中的枚举是完全成熟的Object,它们都扩展为java.lang.Enum,并且都实现了.equals()

所以,你可以存储不同的任何枚举类&#39; java.lang.Enum类型变量中的值,并将其与.equals()进行比较。

,如果你想假装不同枚举类的值是相同的,因为它们共享相同的名称(或者是它们各自类中的第n个常量),你也可以这样做。

请注意,这也意味着自定义枚举可以包含与任何其他类一样的复杂数据和行为,超出它作为唯一标识符使用。

有关详细信息,请参阅Enum API documentation

Java Reflection

其次,Java有广泛的反思支持。出于我们的目的,java.lang.Class有一个名为getEnumConstants()的方法用于获取枚举常量(如果该类不是枚举,则为null)。 有关详细信息,请参阅Class API documentation

循环依赖

第三,至少在涉及泛型时,Java在循环依赖性方面是允许的,因此您可以定义通用接口取决于该泛型的特化。 Java不会介意。