11

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

我有以下界面:

public interface MobileApplication {
    String name();
}

这应该由枚举来实现,因为我需要保证名称的唯一性。当我正在设计一个图书馆时,我不能信任图书馆用户,而且没有唯一的名称,我的图书馆根本无法工作。

我可以不用安全,只是想知道这是否可能。谢谢

4

5 回答 5

17

不幸的是,您不能在编译时真正做到这一点。您可以通过要求类似and之类的方法来给出提示,或者您可以在运行时检查它。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> {
}

总而言之,总会有误用任何库的方法。库作者的目标是让正确使用库比错误使用库更容易。你不需要让它不可能被错误地使用。

于 2012-08-23T09:51:19.703 回答
1

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

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

于 2012-08-23T09:49:47.170 回答
1

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

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

于 2012-08-23T09:51:29.213 回答
1

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

即使你可以,它也无济于事,因为

如果没有唯一的名称,我的库将根本无法工作。

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

您有三个枚举值,都带有name()or ONE

于 2012-08-23T11:17:48.690 回答
1

这不适用于所有应用程序案例,但制定一个使用泛型的库可能是人们未来编写库和研究这个问题的一种出路。

例如,我想编写一个库类 (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) 中的通用 Enum '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);
}

我知道这个答案似乎特定于我的用例,但是对于许多其他想要强制通过枚举实现接口的情况,实现这个想法应该不难。

于 2020-11-28T12:22:27.523 回答