是否可以强制仅通过枚举实现接口?

时间:2012-08-23 09:45:13

标签: java enums

我想知道是否可以强制通过枚举实现接口。

我有以下界面:

public interface MobileApplication {
    String name();
}

这应该由枚举实现,因为我需要保证名称的唯一性。 由于我正在设计一个图书馆,我无法信任图书馆用户,如果没有一个独特的名字,我的图书馆根本无法使用。

我没有安全感,只是想知道是否可能。 感谢

5 个答案:

答案 0 :(得分:16)

不幸的是,你无法在编译时真正做到这一点。您可以通过要求ordinal()name()等方法为此提供提示,或者您可以在运行时进行检查。

关于“我不能信任库用户”:只要您在JavaDoc接口中记录需求,任何不遵循它的人都会获得他所支付的费用。

这与有人没有正确实现equals()hashCode()完全一样:编译器没有强制执行它,但是如果你破坏它,那么依赖它们的类也会破坏它们

你最接近的可能是这样的:

public interface EnumInterface<E extends Enum<E>> {
}

实现如下所示:

public enum MyInterfaceImpl implements EnumInterface<MyInterfaceImpl> {
  FOO,
  BAR;
}

这只是另一个提示,因为“恶意”开发人员仍然可以构建这样的类:

class NotAnEnum implements EnumInterface<MyInterfaceImpl> {
}

总而言之,总是有办法误用任何库。库作者的目标是使更容易正确使用库,而不是错误地使用库。您无需使不可能错误地使用它。

答案 1 :(得分:1)

不是,不。除非你打算提供一个专门检查这个的Java编译器插件。但即便如此,您图书馆的用户也需要愿意使用这样的插件。

因此,只有当库用户希望使用一些静态辅助工具来防止错误时,使用自定义Java编译器插件的方法才有意义。如果您决定使用Java插件选项,This link可能会很有用。

答案 2 :(得分:1)

  

我想知道是否可以强制使用界面   由枚举实现。

不,不是。接口可以由任何类实现,您不能强迫库的用户使用枚举。

答案 3 :(得分:1)

  

我想知道是否可以强制通过枚举实现接口。

即使你能做到它也无济于事,因为

  

没有唯一名称,我的图书馆根本无法使用。

enum A implements MobileApplication {
    ONE
}
enum B implements MobileApplication {
    ONE
}
enum C implements MobileApplication {
    ONE
}

您有三个枚举值,所有值均为name()ONE

答案 4 :(得分:0)

这并非在所有应用程序案例中都有效,但是制定库以使用泛型可能是将来编写库并研究此问题的人们的出路。

例如,我想编写一个库类(SettingsManagerBase),该类通常管理我的应用程序“设置”,并希望保证唯一的密钥能够在代码中获取/设置这些设置。因此,我定义了我的界面(在这里,我还从公认的答案中引入了有关“额外的安全性”的想法,但是严格来讲,这并不是我的方法所必需的):

// Part of my settings library
public interface SettingBase<E extends Enum<E>> {
    Object defaultValue();  // <-- Whatever interface is needed
}

我的实现:

// Part of my application that uses the settings library
public enum Setting implements SettingBase<Setting> {
    THEME,
    SHOW_DIALOGS,
    ...;

    @Override
    public Object defaultValue() { ... }  // <-- Required interface implementation, probably based on constructor arguments (not shown)
}

现在最关键的是,我们的设置管理器库类指定必须为它提供一个实现SettingBase的枚举(这现在是一个总保证):

// Part of my settings library
public abstract class SettingsManagerBase<E extends Enum<E> & SettingBase<E>> {
    public void foo(E setting) {
        Object d = setting.defaultValue();  // We can safely use all methods from our interface
        String n = setting.name();          // We can safely use all enumeration methods, without needing to specify them manually in our interface or anything
    }
}

设置管理器的实现可以是:

// Part of my application that uses the settings library
public class SettingsManager extends SettingsManagerBase<Setting> {
    // If you need to override a function then E just turns into Setting
    public void foo(Setting setting) { ... }
}

如果您需要与库类(SettingsManagerBase)中的通用枚举'E'相对应的类实例,则可以执行以下操作:

// Add to SettingsManagerBase
protected Class<E> mEnumClass;
public SettingsManagerBase(Class<E> enumClass) {
    mEnumClass = enumClass;
    // Now you can do things like call Enum.valueOf(...)
}

// Add to SettingsManager
public SettingsManager() {
    super(Setting.class);
}

我知道这个答案似乎是我的用例所特有的,但是对于许多其他要强制由枚举实现接口的情况来说,要实现这个想法并不难。